zoukankan      html  css  js  c++  java
  • [cf855G]Harry Vs Voldemort

    $(u,v,w)$合法,当且仅当存在一条从$u$到$v$的路径经过$w$(当然$u,v,w$仍要各不相同)

    当$w_{1}$和$w_{2}$之间存在两条无公共边的路径,则$forall u,vin V,(u,v,w_{1})$和$(u,v,w_{2})$合法是等价的

    相当于每一次加入一条边后,就将这条边所产生的环上的点缩起来,之后显然仍是一棵树,重复此过程,那么每一次都是对一棵树统计答案

    用并查集以及维护若干信息即可,求lca时可以暴力向父亲移动,总复杂度即$o(n)$

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 100005
      4 #define ll long long
      5 struct Edge{
      6     int nex,to;
      7 }edge[N<<1];
      8 vector<int>v1,v2;
      9 int E,n,q,x,y,head[N],f[N],fa[N],vis[N],sz[N],Sz[N];
     10 ll ans,sum[N];
     11 ll sqr(int k){
     12     return 1LL*k*k;
     13 }
     14 ll calc(int k){
     15     return 1LL*sz[k]*(1LL*(sz[k]-1)*(n-2)+1LL*(n-1)*(n-sz[k])-sum[k]-sqr(n-Sz[k]));
     16 }
     17 int find(int k){
     18     if (k==fa[k])return k;
     19     return fa[k]=find(fa[k]);
     20 }
     21 void merge(int x,int y){
     22     ans-=calc(y);
     23     fa[y]=x;
     24     sz[x]+=sz[y];
     25     sum[x]+=sum[y];
     26 }
     27 void add(int x,int y){
     28     edge[E].nex=head[x];
     29     edge[E].to=y;
     30     head[x]=E++;
     31 }
     32 void calc(int x,int y){
     33     x=find(x),y=find(y);
     34     v1.clear(),v2.clear();
     35     int lca;
     36     while (1){
     37         if (x){
     38             v1.push_back(x);
     39             if (vis[x]){
     40                 lca=x;
     41                 break;
     42             }
     43             vis[x]=1;
     44             x=find(f[x]);
     45         }
     46         if (y){
     47             v2.push_back(y);
     48             if (vis[y]){
     49                 lca=y;
     50                 break;
     51             }
     52             vis[y]=1;
     53             y=find(f[y]);
     54         }
     55     }
     56     ans-=calc(lca);
     57     for(int i=0;v1[i]!=lca;i++){
     58         merge(lca,v1[i]);
     59         sum[lca]-=sqr(Sz[v1[i]]);
     60     }
     61     for(int i=0;v2[i]!=lca;i++){
     62         merge(lca,v2[i]);
     63         sum[lca]-=sqr(Sz[v2[i]]);
     64     }
     65     ans+=calc(lca);
     66     for(int i=0;i<v1.size();i++)vis[v1[i]]=0;
     67     for(int i=0;i<v2.size();i++)vis[v2[i]]=0;
     68 }
     69 void dfs(int k,int fa){
     70     f[k]=fa;
     71     Sz[k]=1;
     72     for(int i=head[k];i!=-1;i=edge[i].nex)
     73         if (edge[i].to!=fa){
     74             dfs(edge[i].to,k);
     75             Sz[k]+=Sz[edge[i].to];
     76             sum[k]+=sqr(Sz[edge[i].to]);
     77         }
     78 }
     79 int main(){
     80     scanf("%d",&n);
     81     memset(head,-1,sizeof(head));
     82     for(int i=1;i<n;i++){
     83         scanf("%d%d",&x,&y);
     84         add(x,y);
     85         add(y,x); 
     86     }
     87     dfs(1,0);
     88     for(int i=1;i<=n;i++){
     89         fa[i]=i;
     90         sz[i]=1;
     91         ans+=calc(i);
     92     }
     93     printf("%lld
    ",ans);
     94     scanf("%d",&q);
     95     for(int i=1;i<=q;i++){
     96         scanf("%d%d",&x,&y);
     97         calc(x,y);
     98         printf("%lld
    ",ans);
     99     }
    100 }
    View Code
  • 相关阅读:
    What is systemvolumeinformation? delete it?
    What is "found.000" ? How to deal with it?
    install Mac OS on Vmware
    字符串数组全排列
    Hadoop开发相关问题
    String直接赋值和使用new的区别
    输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的
    括号匹配问题
    预编译语句
    两个有序单链表合并成一个有序单链表的java实现
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14817852.html
Copyright © 2011-2022 走看看