dyllalala

导航

[BZOJ 3514]Codechef MARCH14 GERALD07加强版

这题的做法很巧妙,我却写的很作死……

今天算是狠狠的又补了一边 link-cut-tree ,完了又是发现自己很 SX 

考虑已经有 i 条边构成的图,现在要加入第 i+1 跳边

那么有两种情况:1.要么成环 2.要么不成环 (废话)

我们认为成环的边是没有贡献的,不成环的边是有贡献的

答案就是统计 l..r 条边中有贡献的边一共有几条,然后用 n 减一下

我们再次定义第 i 条边加入后构成的环中最早被加入的边是 ntr[i] ,然后从第一条边起,每次在加入第 i 条边后,把第 ntr[i] 条边删除(233…)

此时图始终呈一个生成森林

那么 l..r 条边中有贡献的边的条数就是 l..r 条边中 ntr[i]<l 的边数

因为 ntr[i]>=l 的说明这条边在加入后与 l..i 中的某条边构成了环,显然这是一条毫无贡献的边

ntr 数组可以用 link-cut-tree 来解决,每次在 u 和 v 间连一条权为 w 的边等价于把 u 和 v 连向一个权值为 w 的点,我们就解决了化边权为点权的问题

至于后面那个主席树就可以了……

这真是一道可怕的数据结构题

 

  1 #include <cstdio>
  2 const int inf=0x7FFFFFFF;
  3 const int sizeOfPoint=200002;
  4 
  5 int n, m, k, type;
  6 int u[sizeOfPoint], v[sizeOfPoint];
  7 int time[sizeOfPoint<<1], ntr[sizeOfPoint];
  8 inline int getint();
  9 inline void putint(int);
 10 template<class type> inline void swap(type & a, type & b) {type t=a; a=b; b=t;}
 11 
 12 struct node
 13 {
 14     int id;
 15     node * min;
 16     bool rev;
 17     node * f, * c[2];
 18     inline node():id(0), rev(0) {min=this; f=c[0]=c[1]=this;}
 19     inline void maintain() {min=this; if (time[c[0]->min->id]<time[min->id]) min=c[0]->min; if (time[c[1]->min->id]<time[min->id]) min=c[1]->min;}
 20     inline void pushdown() {if (rev) swap(c[0], c[1]), c[0]->rev^=1, c[1]->rev^=1, rev=0;}
 21 };
 22 node * null=new node();
 23 node memoryOfLct[sizeOfPoint<<1], * portOfLct=memoryOfLct;
 24 node * t[sizeOfPoint<<1];
 25 inline node * newnode(int _id) {node * ret=portOfLct++; ret->id=_id; ret->min=ret; ret->rev=0; ret->f=ret->c[0]=ret->c[1]=null; return ret;}
 26 inline void rotate(node * x, int d) {node * y=x->f, * z=y->f; (y->c[d]=x->c[d^1])->f=y; (x->c[d^1]=y)->f=x; y->maintain(); if (z->c[0]==y) z->c[0]=x; if (z->c[1]==y) z->c[1]=x; x->f=z;}
 27 inline void splay(node * x)
 28 {
 29     node * y, * z; bool d, dd;
 30     x->pushdown();
 31     while ((y=x->f)!=null && (y->c[0]==x || y->c[1]==x))
 32         if ((z=y->f)!=null && (z->c[0]==y || z->c[1]==y))
 33         {
 34             z->pushdown(), y->pushdown(), x->pushdown();
 35             d=y->c[1]==x, dd=z->c[1]==y;
 36             if (d==dd) rotate(y, dd), rotate(x, d);
 37             else rotate(x, d), rotate(x, dd);
 38         }
 39         else
 40         {
 41             y->pushdown(), x->pushdown();
 42             d=y->c[1]==x;
 43             rotate(x, d);
 44         }
 45     x->maintain();
 46 }
 47 inline node * access(node * x) {node * y; for (y=null;x!=null;x=x->f) splay(x), x->c[1]=y, (y=x)->maintain(); return y;}
 48 inline void evert(node * x) {access(x)->rev^=1;}
 49 inline node * find(node * x) {for ( ;x->f!=null;x=x->f); return x;}
 50 inline void link(node * x, node * y) {evert(x); splay(x); x->f=y;}
 51 inline void cut(node * x, node * y) {evert(x); access(y); splay(y); y->c[0]=y->c[0]->f=null;}
 52 inline bool check(node * x, node * y) {return find(x)==find(y);}
 53 inline node * query(node * x, node * y) {evert(x); access(y); splay(y); return y->min;}
 54 
 55 struct seg {int cnt; seg * l, * r; inline seg():cnt(0) {l=r=this;}};
 56 seg * nul=new seg();
 57 seg memoryOfSeg[sizeOfPoint<<6], * portOfSeg=memoryOfSeg;
 58 seg * T[sizeOfPoint];
 59 inline seg * newseg(seg * t=nul) {seg * newt=portOfSeg++; if (t!=nul) newt->cnt=t->cnt, newt->l=t->l, newt->r=t->r; else newt->cnt=0, newt->l=nul, newt->r=nul; return newt;}
 60 seg * insert(seg * , int, int, int);
 61 
 62 inline void prepare();
 63 inline void build();
 64 inline int query(int, int);
 65 
 66 int main()
 67 {
 68     int lastans=0;
 69     int l, r;
 70 
 71     n=getint(); m=getint(); k=getint(); type=getint();
 72     for (int i=1;i<=m;i++) u[i]=getint(), v[i]=getint();
 73     prepare();
 74     build();
 75 
 76 
 77     for (int i=1;i<=k;i++)
 78     {
 79         l=getint(), r=getint();
 80         if (type) l^=lastans, r^=lastans;
 81         putint(lastans=query(l, r));
 82     }
 83 
 84     return 0;
 85 }
 86 inline int getint()
 87 {
 88     register int num=0;
 89     register char ch;
 90     do ch=getchar(); while (ch<'0' || ch>'9');
 91     do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9');
 92     return num;
 93 }
 94 inline void putint(int num)
 95 {
 96     char stack[10];
 97     register int top=0;
 98     if (num==0) stack[top=1]='0';
 99     for ( ;num;num/=10) stack[++top]=num%10+'0';
100     for ( ;top;top--) putchar(stack[top]);
101     putchar('\n');
102 }
103 seg * insert(seg * t, int l, int r, int k)
104 {
105     seg * newt=newseg(t);
106     newt->cnt++;
107     if (l==r) return newt;
108     int m=(l+r)>>1;
109     if (k<=m) newt->l=insert(newt->l, l, m, k);
110     else newt->r=insert(newt->r, m+1, r, k);
111     return newt;
112 }
113 inline void prepare()
114 {
115     for (int i=1;i<=n;i++) t[i]=newnode(i);
116     for (int i=0;i<=n;i++) time[i]=inf;
117     for (int i=1, j=n+1;i<=m;i++, j++)
118     {
119         if (u[i]==v[i]) {ntr[i]=i; continue;}
120         if (check(t[u[i]], t[v[i]]))
121         {
122             node * c=query(t[u[i]], t[v[i]]);
123             ntr[i]=time[c->id];
124             cut(t[u[i]], c); cut(t[v[i]], c);
125         }
126         t[j]=newnode(j); time[j]=i;
127         link(t[u[i]], t[j]); link(t[v[i]], t[j]);
128     }
129 }
130 inline void build()
131 {
132     T[0]=nul;
133     for (int i=1;i<=m;i++)
134         T[i]=insert(T[i-1], 0, m, ntr[i]);
135 }
136 inline int query(int x, int y)
137 {
138     seg * i=T[x-1], * j=T[y];
139     int ret=0;
140     int left=0, right=m, mid;
141     for ( ;j!=nul; )
142     {
143         mid=(left+right)>>1;
144         if (x>mid)
145         {
146             ret+=j->l->cnt-i->l->cnt;
147             i=i->r, j=j->r;
148             left=mid+1;
149         }
150         else
151         {
152             i=i->l, j=j->l;
153             right=mid;
154         }
155     }
156     return n-ret;
157 }
本傻莫名 T 出翔系列

 

posted on 2014-09-18 23:23  dyllalala  阅读(197)  评论(0编辑  收藏  举报