洛谷 P4219 [BJOI2014]大融合

查询,就相当于先删去这条边,然后查询边的两个端点所在连通块大小,乘起来得到答案,然后再把边加回去

可以用线段树分治做

  1 #pragma GCC optimize("Ofast")
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<vector>
  6 #include<map>
  7 using namespace std;
  8 #define fi first
  9 #define se second
 10 #define mp make_pair
 11 #define pb push_back
 12 typedef long long ll;
 13 typedef unsigned long long ull;
 14 typedef pair<int,int> pi;
 15 #define N 100100
 16 struct Q
 17 {
 18     int type,x,y,l,r,num;
 19 }q[N*3];
 20 ll ans[N];
 21 int nq,n,qq,tm,an;
 22 char ss[10];
 23 int fa[N],sz[N],dp[N];
 24 map<pi,int> ma;
 25 int find(int x)
 26 {
 27     for(;x!=fa[x];x=fa[x]);
 28     return x;
 29 }
 30 int bx[N*17],bfa[N*17],bsz[N*17],bdp[N*17],mem;
 31 void unionn(int x,int y)
 32 {
 33     x=find(x),y=find(y);
 34     ++mem;bx[mem]=x;bfa[mem]=fa[x];bsz[mem]=sz[x];bdp[mem]=dp[x];
 35     ++mem;bx[mem]=y;bfa[mem]=fa[y];bsz[mem]=sz[y];bdp[mem]=dp[y];
 36     if(dp[x]<dp[y])    {fa[x]=y;sz[y]+=sz[x];}
 37     else
 38     {
 39         fa[y]=x;sz[x]+=sz[y];
 40         if(dp[x]==dp[y])    dp[x]++;
 41     }
 42 }
 43 void backn(int nn)
 44 {
 45     for(int i=1;i<=nn;i++)
 46     {
 47         fa[bx[mem]]=bfa[mem];sz[bx[mem]]=bsz[mem];dp[bx[mem]]=bdp[mem];--mem;
 48         fa[bx[mem]]=bfa[mem];sz[bx[mem]]=bsz[mem];dp[bx[mem]]=bdp[mem];--mem;
 49     }
 50 }
 51 void solve(int pl,int pr,int l,int r)//[l,r]为线段树上区间
 52 {
 53     if(pl>pr)    return;
 54     int i,nn=0;
 55     if(l==r)
 56     {
 57         for(i=pl;i<=pr;i++)
 58             if(q[i].type==0)
 59                 unionn(q[i].x,q[i].y),++nn;
 60         for(i=pl;i<=pr;i++)
 61             if(q[i].type==1)
 62                 ans[q[i].num]=ll(sz[find(q[i].x)])*sz[find(q[i].y)];
 63         backn(nn);
 64         return;
 65     }
 66     int mid=l+((r-l)>>1),p=pl-1;
 67     for(i=pl;i<=pr;i++)
 68     {
 69         if(q[i].l<=l&&r<=q[i].r)    unionn(q[i].x,q[i].y),++nn;
 70         else    if(q[i].l<=mid)    swap(q[++p],q[i]);
 71     }
 72     solve(pl,p,l,mid);p=pl-1;
 73     for(i=pl;i<=pr;i++)
 74     {
 75         if((q[i].l>l||r>q[i].r)&&mid<q[i].r)    swap(q[++p],q[i]);
 76     }
 77     solve(pl,p,mid+1,r);
 78     backn(nn);
 79 }
 80 int main()
 81 {
 82     int i,x,y;
 83     scanf("%d%d",&n,&qq);
 84     for(i=1;i<=qq;i++)
 85     {
 86         scanf("%s%d%d",ss,&x,&y);
 87         if(x>y)    swap(x,y);
 88         if(ss[0]=='A')
 89         {
 90             ma[mp(x,y)]=++tm;
 91         }
 92         else
 93         {
 94             q[++nq]=(Q){0,x,y,ma[mp(x,y)],++tm,0};
 95             ++tm;q[++nq]=(Q){1,x,y,tm,tm,++an};
 96             ma[mp(x,y)]=++tm;
 97         }
 98     }
 99     for(auto xx:ma)    q[++nq]=(Q){0,xx.fi.fi,xx.fi.se,xx.se,tm,0};
100     for(i=1;i<=n;i++)    fa[i]=i,sz[i]=1;
101     solve(1,nq,1,tm);
102     for(i=1;i<=an;i++)    printf("%lld\n",ans[i]);
103     return 0;
104 }

 

posted @ 2018-07-10 09:35  hehe_54321  阅读(175)  评论(0编辑  收藏  举报
AmazingCounters.com