BZOJ 1095【ZJOI2007】Hide捉迷藏
2016-07-12 16:55
435 查看
题目描述
(2).神奇的线段树搞法
(2).对于两点(u,v)(假设S中u出现在v前面),他们的距离=S[ in[u] , out[v] ]这个括号序列去除掉可匹配的括号,剩下的字符串的长度。
注:最后的字符串都是“)))…..(((“ 的形式,可以将其表示成(a,b),其中a表示“)”的个数,b表示“(”的个数
(3).原问题<=>在S这个线性结构中,找两个黑点之间的最大距离。
用线段树搞,需维护7个信息:
c1,c2:表示(a,b)
dist:维护的答案
Lplus(a1+b1),Lminus(b1-a1)
Rplus(a2+b2),Rminus(a2-b2)
在合并区间(a1,b1),(a2,b2)的时候,
min(b1,a2)可以匹配,需要减去。
<1>.对于a,b
if b1< a2 (a,b)=(a1+a2-b1,b2)
else (a,b)=(a1,b2+b1-a2)
可以写成:
a=a1+max(0,a2-b1)
b=b1+max(0,b1-a2)
<2>.对于a+b
a+b=max( (a1-b1)+(a2+b2) , (a1+b1)+(b2-a2) )
<3>.对于a-b,b-a
a-b=(a1-b1)+(a2-b2)
b-a=(b1-a1)+(b2-a2)
线段树的维护都是建立上述公式上的,具体的写法见代码。
分析:
(1).一道动态树分治的裸题。(2).神奇的线段树搞法
Solution:
(1).将树型结构转换成欧拉序列,成为线性结构。对于每个点u,拥有in[u]和out[u]的起始和终止位置,若将in[u]看作左括号”(“,out[u]看作右括号”)”,这个线性结构就可以看做一个括号序列,记为S。(2).对于两点(u,v)(假设S中u出现在v前面),他们的距离=S[ in[u] , out[v] ]这个括号序列去除掉可匹配的括号,剩下的字符串的长度。
注:最后的字符串都是“)))…..(((“ 的形式,可以将其表示成(a,b),其中a表示“)”的个数,b表示“(”的个数
(3).原问题<=>在S这个线性结构中,找两个黑点之间的最大距离。
用线段树搞,需维护7个信息:
c1,c2:表示(a,b)
dist:维护的答案
Lplus(a1+b1),Lminus(b1-a1)
Rplus(a2+b2),Rminus(a2-b2)
在合并区间(a1,b1),(a2,b2)的时候,
min(b1,a2)可以匹配,需要减去。
<1>.对于a,b
if b1< a2 (a,b)=(a1+a2-b1,b2)
else (a,b)=(a1,b2+b1-a2)
可以写成:
a=a1+max(0,a2-b1)
b=b1+max(0,b1-a2)
<2>.对于a+b
a+b=max( (a1-b1)+(a2+b2) , (a1+b1)+(b2-a2) )
<3>.对于a-b,b-a
a-b=(a1-b1)+(a2-b2)
b-a=(b1-a1)+(b2-a2)
线段树的维护都是建立上述公式上的,具体的写法见代码。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 100000 #define INF 1000000000 int n,mark[MAXN+10],b[MAXN*3+10],cntb,pos[MAXN+10]; bool vis[MAXN+10]; struct SegmentTree{ int c1,c2,Lp,Lm,Rp,Rm,dist; //(a,b) //c1:a //c2:b //Lp:Lplus (a1+b1) //Lm:Lminus (b1-a1) //Rp:Rplus (a2+b2) //Rm:Rminus (a2-b2) //dist:ans void val(int x){ c1=c2=0; Lp=Lm=Rp=Rm=dist=-INF; if(x==-1) c2=1; else if(x==-2) c1=1; else if(mark[x]==1) Lp=Lm=Rp=Rm=dist=0; } void Update(const SegmentTree &a,const SegmentTree &b){ c1=a.c1+max(0,b.c1-a.c2); c2=b.c2+max(0,a.c2-b.c1); //a+b = max( (a1-b1)+(a2+b2) , (a1+b1)+(b2-a2) ) dist=max(max(a.dist,b.dist),max(a.Rp+b.Lm,a.Rm+b.Lp)); Lp=max(a.Lp,max(a.c1+a.c2+b.Lm,a.c1-a.c2+b.Lp)); Rp=max(b.Rp,max(a.Rm+b.c1+b.c2,a.Rp-b.c1+b.c2)); //a-b = (a1-b1) + (a2-b2) Lm=max(a.Lm,(a.c2-a.c1)+b.Lm); Rm=max(b.Rm,(b.c1-b.c2)+a.Rm); } }tre[(MAXN*3)*4+10]; struct node{ int v; node *next; }edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0]; void Read(int &x){ char c; while(c=getchar(),c!=EOF){ if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return ; } } } void addedge(int u,int v){ node *p=++ecnt; p->v=v; p->next=adj[u]; adj[u]=p; } void dfs(int u) { vis[u]=true; b[++cntb]=-1; b[++cntb]=u; pos[u]=cntb; for(node *p=adj[u];p;p=p->next) if(!vis[p->v]) dfs(p->v); b[++cntb]=-2; } void read() { int x,y; Read(n); for(int i=1;i<n;i++){ Read(x),Read(y); addedge(x,y); addedge(y,x); } dfs(1); } void Build(int u,int l,int r) { if(l==r){ tre[u].val(b[l]); return ; } int mid=(l+r)>>1; Build(u<<1,l,mid),Build((u<<1)|1,mid+1,r); tre[u].Update(tre[u<<1],tre[(u<<1)|1]); } void Modify(int u,int l,int r,int pos) { if(l==r){ tre[u].val(b[l]); return ; } int mid=(l+r)>>1; if(pos<=mid) Modify(u<<1,l,mid,pos); else Modify((u<<1)|1,mid+1,r,pos); tre[u].Update(tre[u<<1],tre[(u<<1)|1]); } int main() { int Q,x,cnt; char opt[100]; read(); for(int i=1;i<=n;i++) mark[i]=1; //mark: (1):关灯 (-1):开灯 cnt=n; Build(1,1,cntb); Read(Q); while(Q--){ scanf("%s",opt); if(opt[0]=='C'){ Read(x); cnt+=(mark[x]=-mark[x]); Modify(1,1,cntb,pos[x]); } else{ if(cnt==0) puts("-1"); else if(cnt==1) puts("0"); else printf("%d\n",tre[1].dist); } } }