bzoj 1095 ZJOI2007 捉迷藏

  额,这个题巨恶心啦~

  树分治不会写,只能翻论文写括号序列了,cqx把每个点分成了三分"(",“)”,数字,那么两个数字之间未匹配的括号数就是两个点之间的距离,然后我们要求的就是两个黑点之间的距离,于是就可以用线段树维护了吧。

  最恶心的就是维护了,要维护6个量,左括号总数,右括号总数,前缀和,前缀差,后缀和,后缀差(只是简称),合并的时候用后4个量可以得到区间的最大距离,然后这6个量之间可以互相更新,不行我已经晕了,如果有兴趣的话去看看cqx的论文吧,贴个代码帮助有耐心的人差错......

  对于黑白点的处理,就吧白点的后4个量设为-inf,黑点的后4个量设为0,就可以了。

  

hide
  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了......后来发现数组还开小了。为什么我的常数这么大!!!

转载于:https://www.cnblogs.com/zig-zag/archive/2013/04/18/3028956.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值