SPOJ QTREE4

You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3...,N. Each edge has an integer value assigned to it(note that the value can be negative). Each node has a color, white or black. We define dist(a, b) as the sum of the value of the edges on the path from node a to node b.

All the nodes are white initially.

We will ask you to perfrom some instructions of the following form:

  • C a : change the color of node a.(from black to white or from white to black)
  • A : ask for the maximum dist(a, b), both of node a and node b must be white(a can be equal to b). Obviously, as long as there is a white node, the result will alway be non negative.

Input

  • In the first line there is an integer N (N <= 100000)
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of value c (-1000 <= c <= 1000)
  • In the next line, there is an integer Q denotes the number of instructions (Q <= 100000)
  • In the next Q lines, each line contains an instruction "C a" or "A"

Output

For each "A" operation, write one integer representing its result. If there is no white node in the tree, you should write "They have disappeared.".

Example

Input:
3
1 2 1
1 3 1
7
A
C 1
A
C 2
A
C 3
A

Output:
2
2
0
They have disappeared.

给出一棵边带权的树,初始树上所有节点都是白色。
有两种操作:

C x,改变节点x的颜色,即白变黑,黑变白

A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为0)。

树 边分治

试着写了边分治,花式WAWAWA,最后不得已还是开启了标准代码比对

这么复杂的东西估计过几天就忘,悲伤

果然加上虚点以后内存占用超大啊……边要开到mxn<<4

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 const int INF=1e8;
  8 const int mxn=200010;
  9 int read(){
 10     int x=0,f=1;char ch=getchar();
 11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 12     while(ch>='0' && ch<='9'){x=x*10-'0'+ch;ch=getchar();}
 13     return x*f;
 14 }
 15 struct edge{
 16     int v,nxt;int w;
 17 }e[mxn<<4],eg[mxn<<2];
 18 int hd[mxn],mct=1;
 19 int tmp[mxn];
 20 void add_edge(int u,int v,int w){//虚点图 
 21     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].w=w;hd[u]=mct;return;
 22 }
 23 void add1(int u,int v,int w){//原图 
 24     eg[++mct].v=v;eg[mct].nxt=tmp[u];eg[mct].w=w;tmp[u]=mct;return;
 25 }
 26 int n,m;
 27 int c[mxn];//颜色
 28 
 29 void Rebuild(int u,int fa){//建立添加了虚点的新图 
 30     int ff=0;
 31     for(int i=tmp[u];i;i=eg[i].nxt){//tmp存原图边 
 32         int v=eg[i].v;
 33         if(v==fa)continue;
 34         if(!ff){
 35             add_edge(u,v,eg[i].w);
 36             add_edge(v,u,eg[i].w);
 37             ff=u;
 38             Rebuild(v,u);
 39         }
 40         else{
 41             c[++n]=1;//添加虚点
 42             add_edge(ff,n,0);add_edge(n,ff,0);
 43             add_edge(n,v,eg[i].w);
 44             add_edge(v,n,eg[i].w);
 45             ff=n;
 46             Rebuild(v,u);
 47         }
 48     }
 49     return;
 50 }
 51 struct node{
 52     int rt,len,ans;
 53     int lc,rc;
 54     priority_queue<pair<int,int> >q;
 55 }t[mxn<<2];
 56 bool del[mxn<<2];
 57 int pos,mini,mid;
 58 int sz[mxn],tot=0;
 59 void DFS_S(int u,int d,int fa){//计算子树各结点距离 
 60     add1(u,pos,d);//用原图的空间来存边分治的点边关系
 61     //从当前结点向"管辖它的边代表的结点"连边 
 62     if(!c[u]) t[pos].q.push(make_pair(d,u));
 63     sz[u]=1;
 64     for(int i=hd[u];i;i=e[i].nxt){
 65         int v=e[i].v;    
 66         if(v==fa || del[i])continue;
 67         DFS_S(v,d+e[i].w,u);
 68         sz[u]+=sz[v];
 69     }
 70     return;
 71 }
 72 void DFS_mid(int u,int id){
 73     if(max(sz[u],sz[t[pos].rt]-sz[u])<mini){//寻找中心边 
 74         mini=max(sz[u],sz[t[pos].rt]-sz[u]);
 75         mid=id;
 76     }
 77     for(int i=hd[u];i;i=e[i].nxt){
 78         if(i!=(id^1) && !del[i]){
 79             DFS_mid(e[i].v,i);
 80         }
 81     }
 82     return;
 83 }
 84 void pushup(int p){//处理编号为rt的中心边 
 85     t[p].ans=-1;
 86     while(!t[p].q.empty() && (c[t[p].q.top().second]==1)) t[p].q.pop();
 87 //    printf("rt:%d lc:%d rc:%d
",p,t[p].lc,t[p].rc);
 88     if(!t[p].lc && !t[p].rc){if(!c[t[p].rt])t[p].ans=0;}
 89     else{
 90         int tmp=max(t[t[p].lc].ans,t[t[p].rc].ans);
 91         t[p].ans=max(t[p].ans,tmp);
 92         if(!t[t[p].lc].q.empty() && !t[t[p].rc].q.empty())
 93             t[p].ans=max(t[t[p].lc].q.top().first+t[t[p].rc].q.top().first+t[p].len,t[p].ans);
 94     }
 95     return;
 96 }
 97 void update(int u){
 98     c[u]^=1;
 99     if(c[u])
100         for(int i=tmp[u];i;i=eg[i].nxt){
101             pushup(eg[i].v);
102         }
103     else for(int i=tmp[u];i;i=eg[i].nxt){
104         t[eg[i].v].q.push(make_pair(eg[i].w,u));
105         pushup(eg[i].v);
106     }
107 }
108 void divide(int u,int p){//边分治 
109     t[p].rt=u;
110     pos=p;
111     DFS_S(u,0,0);
112     mid=-1;mini=INF;
113     DFS_mid(u,-1);
114     if(mid>0){
115         del[mid]=1;del[mid^1]=1;
116         int x=e[mid].v,y=e[mid^1].v;//先保存两边的点,否则递归过程中mid变了会导致WA
117         t[p].len=e[mid].w;
118         t[p].lc=++tot;
119         t[p].rc=++tot;
120         divide(x,t[p].lc);
121         divide(y,t[p].rc);
122     }
123     pushup(p);
124 }
125 int main(){
126     int i,j,u,v,w;
127     n=read();
128     mct=6*n;
129     for(i=1;i<n;i++){
130         u=read();v=read();w=read();
131         add1(u,v,w);add1(v,u,w);
132     }
133     mct=1;
134     Rebuild(1,0);
135     memset(tmp,0,sizeof tmp);//初始化原图 
136     mct=1;
137     tot=1;
138     divide(1,tot);    
139     char op[5];
140     m=read();
141     while(m--){
142         scanf("%s",op);
143         if(op[0]=='A'){
144             if(t[1].ans>=0)
145                 printf("%d
",t[1].ans);
146             else printf("They have disappeared.
");
147         }
148         else{
149             w=read();
150             update(w);
151         }
152     }
153     return 0;
154 }
原文地址:https://www.cnblogs.com/SilverNebula/p/6361425.html