额,这个题巨恶心啦~
树分治不会写,只能翻论文写括号序列了,cqx把每个点分成了三分"(",“)”,数字,那么两个数字之间未匹配的括号数就是两个点之间的距离,然后我们要求的就是两个黑点之间的距离,于是就可以用线段树维护了吧。
最恶心的就是维护了,要维护6个量,左括号总数,右括号总数,前缀和,前缀差,后缀和,后缀差(只是简称),合并的时候用后4个量可以得到区间的最大距离,然后这6个量之间可以互相更新,不行我已经晕了,如果有兴趣的话去看看cqx的论文吧,贴个代码帮助有耐心的人差错......
对于黑白点的处理,就吧白点的后4个量设为-inf,黑点的后4个量设为0,就可以了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 1250000 7 #define inf 12345678 8 using namespace std; 9 int fir[maxn],pos[maxn],col[maxn],d[maxn]; 10 int la[maxn],ra[maxn],lb[maxn],rb[maxn],ls[maxn],rs[maxn],dis[maxn]; 11 struct et 12 { 13 int s,t,next; 14 }e[maxn]; 15 int n,m,tot,cnt,num; 16 17 inline void dfs(int now) 18 { 19 d[++cnt]=-1; 20 d[++cnt]=now; 21 pos[now]=cnt; 22 for (int j=fir[now];j;j=e[j].next) 23 { 24 int k=e[j].t; 25 if (!pos[k]) dfs(k); 26 } 27 d[++cnt]=-2; 28 } 29 30 inline void setup(int now,int x) 31 { 32 ls[now]=(d[x]==-2); 33 rs[now]=(d[x]==-1); 34 dis[now]=-inf; 35 la[now]=ra[now]=lb[now]=rb[now]=(d[x]>0 && col[d[x]]==0)?0:-inf; 36 } 37 38 inline void update(int x) 39 { 40 int q=x*2,p=x*2+1; 41 ls[x]=ls[q]+max(0,ls[p]-rs[q]);//ls是未匹配的朝左括号 42 rs[x]=rs[p]+max(0,rs[q]-ls[p]);//rs是未匹配的朝右括号 43 dis[x]=max(max(dis[q],dis[p]),max(ra[q]+lb[p],rb[q]+la[p]));//dis是最远距离 44 la[x]=max(la[q],max(ls[q]+rs[q]+lb[p],ls[q]-rs[q]+la[p]));//la是包含左端点的最大未匹配和 45 lb[x]=max(lb[q],rs[q]-ls[q]+lb[p]);//lb是包含左端点的最大匹配差(即最少翻转几个) 46 ra[x]=max(ra[p],max(rs[p]+ls[p]+rb[q],rs[p]-ls[p]+ra[q]));//ra是包含右端点的最大未匹配和 47 rb[x]=max(rb[p],ls[p]-rs[p]+rb[q]);//rb是包含右端点的最大匹配差 48 } 49 50 inline void build(int now,int l,int r) 51 { 52 if (l==r) 53 { 54 setup(now,l); 55 return ; 56 } 57 int mid=(l+r)>>1; 58 build(now*2,l,mid); 59 build(now*2+1,mid+1,r); 60 update(now); 61 } 62 63 inline void change(int now,int l,int r,int x) 64 { 65 if (l==r) 66 { 67 setup(now,l); 68 return ; 69 } 70 int mid=(l+r)>>1; 71 if (x<=mid) change(now*2,l,mid,x); 72 else change(now*2+1,mid+1,r,x); 73 update(now); 74 } 75 76 inline void add(int x,int y) 77 { 78 e[++tot].s=x; e[tot].t=y; e[tot].next=fir[x]; fir[x]=tot; 79 e[++tot].s=y; e[tot].t=x; e[tot].next=fir[y]; fir[y]=tot; 80 } 81 82 int main() 83 { 84 //freopen("hide.in","r",stdin); 85 scanf("%d",&n); 86 num=n; 87 int x,y; 88 for (int i=1;i<n;i++) 89 { 90 scanf("%d%d",&x,&y); 91 add(x,y); 92 } 93 int rot=1; 94 dfs(rot); 95 build(1,1,cnt); 96 scanf("%d",&m); 97 char sign[10]; 98 for (int i=1;i<=m;i++) 99 { 100 scanf("%s",sign); 101 if (sign[0]=='G') 102 { 103 if (num==0) printf("-1\n"); 104 else 105 if (num==1) printf("0\n"); 106 else printf("%d\n",dis[1]); 107 } 108 else 109 { 110 scanf("%d\n",&x); 111 if (col[x]==0) col[x]=1,num--; 112 else col[x]=0,num++; 113 change(1,1,cnt,pos[x]); 114 } 115 } 116 return 0; 117 }
P.S.我一开始把inf设成-2147483647了,于是......两个一加变成正的inf了......后来发现数组还开小了。为什么我的常数这么大!!!