bzoj 1095 ZJOI2007 捉迷藏
2013-04-18 16:50
218 查看
额,这个题巨恶心啦~
树分治不会写,只能翻论文写括号序列了,cqx把每个点分成了三分"(",“)”,数字,那么两个数字之间未匹配的括号数就是两个点之间的距离,然后我们要求的就是两个黑点之间的距离,于是就可以用线段树维护了吧。
最恶心的就是维护了,要维护6个量,左括号总数,右括号总数,前缀和,前缀差,后缀和,后缀差(只是简称),合并的时候用后4个量可以得到区间的最大距离,然后这6个量之间可以互相更新,不行我已经晕了,如果有兴趣的话去看看cqx的论文吧,贴个代码帮助有耐心的人差错......
对于黑白点的处理,就吧白点的后4个量设为-inf,黑点的后4个量设为0,就可以了。
hide
P.S.我一开始把inf设成-2147483647了,于是......两个一加变成正的inf了......后来发现数组还开小了。为什么我的常数这么大!!!
树分治不会写,只能翻论文写括号序列了,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了......后来发现数组还开小了。为什么我的常数这么大!!!
相关文章推荐
- BZOJ1095 [ZJOI2007]Hide 捉迷藏
- BZOJ1095: [ZJOI2007]Hide 捉迷藏
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
- BZOJ1095 [ZJOI2007]Hide 捉迷藏
- bzoj 1095: [ZJOI2007]Hide 捉迷藏
- 「BZOJ1095」[ZJOI2007] Hide 捉迷藏
- BZOJ1095: [ZJOI2007]Hide 捉迷藏
- 【BZOJ 1095】 [ZJOI2007]Hide 捉迷藏
- bzoj1095[ZJOI2007]捉迷藏
- 【BZOJ1095】【ZJOI2007】捉迷藏 [动态点分治]
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
- BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆
- bzoj1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树/动态点分治+堆)
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 【动态点分治 + 堆】
- 【bzoj1095】 ZJOI2007—捉迷藏
- BZOJ1095: [ZJOI2007]Hide 捉迷藏
- [BZOJ1095][ZJOI2007][线段树]Hide捉迷藏
- 【BZOJ1095】【ZJOI2007】Hide 捉迷藏
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏