結果
| 問題 |
No.772 Dynamic Distance Sum
|
| コンテスト | |
| ユーザー |
kriii
|
| 提出日時 | 2018-12-21 11:00:18 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
RE
|
| 実行時間 | - |
| コード長 | 5,653 bytes |
| コンパイル時間 | 801 ms |
| コンパイル使用メモリ | 81,100 KB |
| 実行使用メモリ | 52,480 KB |
| 最終ジャッジ日時 | 2024-09-25 09:17:41 |
| 合計ジャッジ時間 | 6,051 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 2 RE * 25 |
ソースコード
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
using namespace std;
struct Node{
Node(int weight_ = 1, int len_ = 0)
{
left = right = parent = nullptr;
weight[0] = weight_; weight[1] = len_;
size[0] = weight[0]; size[1] = weight[1]; hSize = 0;
sum[0] = sum[1] = hSum = 0;
reverse = false;
}
~Node()
{
makeRoot();
if (right) right->parent = nullptr;
for (auto &p : hNode) p.second->parent = nullptr;
}
Node *left, *right, *parent;
long long weight[2], size[2], hSize, sum[2], hSum;
bool reverse;
set<pair<int, Node*> > hNode; // loser.
bool isRoot();
void propagate();
void update();
void rotate();
void splay();
Node* access();
void hidePath();
void chainPath(Node *node);
void makeRoot();
void link(Node *node);
void cut();
void changeWeight(int weight);
Node* findCenter();
};
struct LinkCutTree
{
LinkCutTree(){}
LinkCutTree(int size)
{
nodeList.resize(size);
for (int i=0;i<size;i++) nodeList[i] = new Node;
}
vector<Node*> nodeList;
void addNode(int weight = 1, int len = 0)
{
nodeList.emplace_back(new Node(weight, len));
}
Node* getNode(int i)
{
if (0 <= i && i < nodeList.size()) return nodeList[i];
return nullptr;
}
};
bool Node::isRoot()
{
return this == nullptr || parent == nullptr || (parent->left != this && parent->right != this);
}
void Node::propagate()
{
if (reverse){
swap(left, right);
swap(sum[0],sum[1]);
if (left) left->reverse = !left->reverse;
if (right) right->reverse = !right->reverse;
reverse = false;
}
}
void Node::update()
{
size[0] = weight[0] + hSize;
size[1] = weight[1];
sum[0] = sum[1] = hSum;
long long psum[2] = {size[0],size[0]}, qsum[2] = {size[1],size[1]};
if (left){
size[0] += left->size[0];
size[1] += left->size[1];
psum[1] += left->size[0];
qsum[0] += left->size[1];
}
if (right){
size[0] += right->size[0];
size[1] += right->size[1];
psum[0] += right->size[0];
qsum[1] += right->size[1];
}
for (int k=0;k<2;k++){
if (left) sum[k] += left->sum[k^left->reverse];
if (right) sum[k] += right->sum[k^right->reverse];
sum[k] += psum[k] * qsum[k];
}
}
void Node::rotate()
{
if (isRoot())
return;
Node *up = parent;
up->propagate();
propagate();
Node *jump = up->parent;
up->parent = this;
Node *down = nullptr;
if (up->left == this){
up->left = down = right;
right = up;
}
else{
up->right = down = left;
left = up;
}
if (down) down->parent = up;
parent = jump;
if (jump){
int sz = up->size[0];
auto I = jump->hNode.find({sz, up});
if (I != jump->hNode.end()){
jump->hNode.erase(I);
jump->hNode.insert({sz, this});
}
else if (jump->left == up)
jump->left = this;
else if (jump->right == up)
jump->right = this;
}
up->update();
update();
}
void Node::splay()
{
propagate();
while (!isRoot()){
Node *up = parent;
if (!up->isRoot()){
Node *jump = up->parent;
if ((this == up->left) ^ (up == jump->left))
rotate();
else
up->rotate();
}
rotate();
}
}
Node* Node::access()
{
hidePath();
Node* last = this;
while (parent){
last = parent;
parent->chainPath(this);
splay();
}
return last;
}
void Node::hidePath()
{
splay();
if (right && right->parent == this){
hSize += right->size[0];
hSum += right->sum[right->reverse];
hNode.insert({right->size[0], right});
right = nullptr;
update();
}
}
void Node::chainPath(Node *node)
{
hidePath();
if (node && node->parent == this && left != node){
right = node;
hSize -= right->size[0];
hSum -= right->sum[right->reverse];
hNode.erase({right->size[0], right});
update();
}
}
void Node::makeRoot()
{
access();
reverse = !reverse;
propagate();
}
void Node::link(Node *node)
{
if (!node)
return;
makeRoot();
access();
node->access();
left = node;
node->parent = this;
update();
}
void Node::cut()
{
if (!parent) return;
access();
if (left){
left->parent = nullptr;
left = nullptr;
}
splay();
}
void Node::changeWeight(int weight_)
{
makeRoot();
weight[0] = weight_;
update();
}
Node* Node::findCenter()
{
makeRoot();
int full = size[0];
if (full == 0) return this;
int half = full / 2;
Node *n = this;
while (true){
n->propagate();
if (n->left){
if (full - n->size[0] + n->left->size[0] > half){
n = n->left;
continue;
}
}
if (n->right){
if (n->right->size[0] > half){
n = n->right;
continue;
}
}
if (!n->hNode.empty()){
auto I = n->hNode.end(); --I;
if (I->first > half){
n->splay();
n = I->second;
continue;
}
}
break;
}
n->makeRoot();
return n;
}
int main()
{
int N,Q; scanf ("%d %d",&N,&Q);
LinkCutTree lct(N);
map<pair<int, int>, Node *> edge;
int enc = 0;
while (Q--){
int o; scanf ("%d",&o);
if (o == 1){
int x,y,c; scanf ("%d %d %d",&x,&y,&c);
x = (x - 1 + enc) % N;
y = (y - 1 + enc) % N;
if (x > y) swap(x,y);
Node *e = new Node(0,c);
Node *p = lct.getNode(x);
Node *q = lct.getNode(y);
p->access();
Node *t = q->access();
if (t == p->access()){
return 1;
}
p->link(e);
q->link(e);
edge[{x,y}] = e;
}
else if (o == 2){
int x,y; scanf ("%d %d",&x,&y);
x = (x - 1 + enc) % N;
y = (y - 1 + enc) % N;
if (x > y) swap(x,y);
auto I = edge.find({x,y});
if (I != edge.end()){
delete I->second;
edge.erase(I);
}
}
else if (o == 3){
int x; scanf ("%d",&x);
x = (x - 1 + enc) % N;
auto v = lct.getNode(x);
v->changeWeight(1 - v->weight[0]);
auto c = v->findCenter();
long long res = c->sum[c->reverse];
enc = (enc + res) % N;
printf ("%lld\n",res);
}
}
return 0;
}
kriii