您的位置:首页 > 其它

bzoj 1095 ZJOI2007 捉迷藏

2013-04-18 16:50 218 查看
  额,这个题巨恶心啦~

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

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

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

  

hide

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define maxn 1250000
#define inf 12345678
using namespace std;
int fir[maxn],pos[maxn],col[maxn],d[maxn];
int la[maxn],ra[maxn],lb[maxn],rb[maxn],ls[maxn],rs[maxn],dis[maxn];
struct et
{
int s,t,next;
}e[maxn];
int n,m,tot,cnt,num;

inline void dfs(int now)
{
d[++cnt]=-1;
d[++cnt]=now;
pos[now]=cnt;
for (int j=fir[now];j;j=e[j].next)
{
int k=e[j].t;
if (!pos[k]) dfs(k);
}
d[++cnt]=-2;
}

inline void setup(int now,int x)
{
ls[now]=(d[x]==-2);
rs[now]=(d[x]==-1);
dis[now]=-inf;
la[now]=ra[now]=lb[now]=rb[now]=(d[x]>0 && col[d[x]]==0)?0:-inf;
}

inline void update(int x)
{
int q=x*2,p=x*2+1;
ls[x]=ls[q]+max(0,ls[p]-rs[q]);//ls是未匹配的朝左括号
rs[x]=rs[p]+max(0,rs[q]-ls[p]);//rs是未匹配的朝右括号
dis[x]=max(max(dis[q],dis[p]),max(ra[q]+lb[p],rb[q]+la[p]));//dis是最远距离
la[x]=max(la[q],max(ls[q]+rs[q]+lb[p],ls[q]-rs[q]+la[p]));//la是包含左端点的最大未匹配和
lb[x]=max(lb[q],rs[q]-ls[q]+lb[p]);//lb是包含左端点的最大匹配差(即最少翻转几个)
ra[x]=max(ra[p],max(rs[p]+ls[p]+rb[q],rs[p]-ls[p]+ra[q]));//ra是包含右端点的最大未匹配和
rb[x]=max(rb[p],ls[p]-rs[p]+rb[q]);//rb是包含右端点的最大匹配差
}

inline void build(int now,int l,int r)
{
if (l==r)
{
setup(now,l);
return ;
}
int mid=(l+r)>>1;
build(now*2,l,mid);
build(now*2+1,mid+1,r);
update(now);
}

inline void change(int now,int l,int r,int x)
{
if (l==r)
{
setup(now,l);
return ;
}
int mid=(l+r)>>1;
if (x<=mid) change(now*2,l,mid,x);
else change(now*2+1,mid+1,r,x);
update(now);
}

inline void add(int x,int y)
{
e[++tot].s=x; e[tot].t=y; e[tot].next=fir[x]; fir[x]=tot;
e[++tot].s=y; e[tot].t=x; e[tot].next=fir[y]; fir[y]=tot;
}

int main()
{
//freopen("hide.in","r",stdin);
scanf("%d",&n);
num=n;
int x,y;
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
int rot=1;
dfs(rot);
build(1,1,cnt);
scanf("%d",&m);
char sign[10];
for (int i=1;i<=m;i++)
{
scanf("%s",sign);
if (sign[0]=='G')
{
if (num==0) printf("-1\n");
else
if (num==1) printf("0\n");
else printf("%d\n",dis[1]);
}
else
{
scanf("%d\n",&x);
if (col[x]==0) col[x]=1,num--;
else col[x]=0,num++;
change(1,1,cnt,pos[x]);
}
}
return 0;
}


P.S.我一开始把inf设成-2147483647了,于是......两个一加变成正的inf了......后来发现数组还开小了。为什么我的常数这么大!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: