2018 ACM-ICPC青岛现场赛 B题 Kawa Exam 题解 ZOJ 4059

题意:
BaoBao正在进行在线考试(都是选择题),每一个题都有惟一的一个正确答案,可是考试系统有m个bug(就是有m个限制),每一个bug表示为第u个问题和第v个问题你必须选择相同的选项,题目问你,若是你修好了第i个bug,BaoBao最高能够取得多少分。node

题目数量1e5
BUG数量1e5(真多)
答案范围1e5c++

思路:首先,若是出现了bug,致使{a1,a2,...,an}n个题目必须选择同样的结果,那么最高得分确定是众数的出现次数。咱们发现bug是具备传递性的,若是bug连成了一个环,并且你只修复其中一个bug,那么这个bug的修复是对整个考试系统是没有任何影响的,因此咱们不须要考虑这个环内的边,而后咱们能够把这些环抠出来,缩成一个点,具体的缩点方法不少,也能够把整个块拉成一条链或者拓扑排序弄一弄,或者tarjan缩一下,我是用tarjan缩点的,这样整个图就是一个树了。
如今修一个bug就至关于断了一条边,一棵树就被切成两半了,咱们须要同时获得两边的众数的个数是多少,这时候就有一个算法叫dsu on tree了,这是一个复杂度十分科学的暴力算法,http://codeforces.com/problemset/problem/600/E 这个题是一个dsu on tree的裸题,就是让你求每一个子树的众数,不会这个算法的能够去学一下,作完这个题你就发现你会作子树内众数的个数了,如今还有个问题,子树外的怎么求呢?咱们能够反过来作,一开始把全部的节点加进贡献里面去,而后dsu on tree的时候,询问子树众数的添加删除的时候,咱们只要作相反的操做就好了。算法

具体细节还挺多的。spa

 

 1 #include<bits/stdc++.h>
 2 using namespace std;  3 const int maxn = 100010;struct Edge {  4     int to,next,id;  5     Edge(int _to=0,int _next=-1,int _id=0):to(_to),next(_next),id(_id) {};  6 } edge[maxn*2];  7 int head[maxn],etot;  8 inline void addedge(int u,int v,int id) {  9     edge[++etot]=Edge(v,head[u],id);  10     head[u]=etot;  11 }  12 vector<int> nodes[maxn];  13 int Cnt;  14 int dfn[maxn],low[maxn],tot;  15 bool Vis[maxn];  16 int S[maxn],top;  17 int id[maxn];  18 void tarjan(int x,int fa) {  19     low[x]=dfn[x]=++tot;  20     S[++top]=x;  21     Vis[x]=1;  22     for(register int i=head[x]; ~i; i=edge[i].next) {  23         int v=edge[i].to;  24         if(v==fa) {fa=0;continue;}  25         if(!dfn[v]) {  26  tarjan(v,x);  27             low[x]=min(low[x],low[v]);  28         } else if(Vis[v])  29             low[x]=min(low[x],dfn[v]);  30  }  31     if(low[x]==dfn[x]) {  32         Cnt++;  33         while(1) {  34             int now=S[top--];  35             Vis[now]=0;  36             id[now]=Cnt;  37  nodes[Cnt].push_back(now);  38             if(now==x) break;  39  }  40  }  41 }  42 int a[maxn],ans[maxn];  43 vector<int>v[maxn];  44 vector<int>edg[maxn],eid[maxn];  45 int summ;  46 bool vis[maxn];  47 int sz[maxn],son[maxn];  48 vector<int>vv;  49 int getid(int x) {  50     return lower_bound(vv.begin(),vv.end(),x)-vv.begin()+1;  51 }  52 void init(int now,int pre=-1){  53     vis[now]=1;  54     sz[now]=v[now].size();  55     for(int it:v[now])vv.push_back(a[it]);  56     for(int to:edg[now]){  57         if(to==pre)continue;  58  init(to,now);  59         sz[now]+=sz[to];  60         if(!son[now]||sz[to]>sz[son[now]])  61             son[now]=to;  62  }  63 }  64 int tp[maxn],tp2[maxn],cnt[maxn],cnt2[maxn],Max=0,Max2=0;  65 bool big[maxn];  66 void update(int nows,int pre,int val){  67     for(int now:v[nows]){  68         tp[cnt[a[now]]]--;  69         cnt[a[now]]+=val;  70         tp[cnt[a[now]]]++;  71         if(cnt[a[now]]>Max)  72             Max=cnt[a[now]];  73         if(!tp[Max])Max--;  74         tp2[cnt2[a[now]]]--;  75         cnt2[a[now]]-=val;  76         tp2[cnt2[a[now]]]++;  77         if(cnt2[a[now]]>Max2)  78             Max2=cnt2[a[now]];  79         if(!tp2[Max2])Max2--;  80  }  81     for(int to:edg[nows])  82         if(to!=pre&&big[to]==0)  83  update(to,nows,val);  84 }  85 void update2(int nows,int pre,int val){  86     for(int now:v[nows]){  87         tp2[cnt2[a[now]]]--;  88         cnt2[a[now]]+=val;  89         tp2[cnt2[a[now]]]++;  90         if(cnt2[a[now]]>Max2)  91             Max2=cnt2[a[now]];  92         if(!tp2[Max2])Max2--;  93  }  94 }  95 int temp;  96 void dfs(int now,int pre=-1,int kep=0,int id=0){  97     int tid=0;  98     for(register int i=0;i<edg[now].size();i++){  99         int to=edg[now][i]; 100         if(to==son[now])tid=eid[now][i]; 101         if(to==pre||to==son[now])continue; 102         dfs(to,now,0,eid[now][i]); 103  } 104     if(son[now]) 105         dfs(son[now],now,1,tid),big[son[now]]=1; 106     update(now,pre,1); 107     ans[id]=Max+Max2-temp; 108     big[son[now]]=0; 109     if(!kep)update(now,pre,-1); 110 } 111 void init2(int now,int pre=-1){ 112     for(int it:v[now])a[it]=getid(a[it]); 113     update2(now,0,1); 114     for(int to:edg[now]){ 115         if(to==pre)continue; 116  init2(to,now); 117  } 118 } 119 void solve(int now){ 120  vv.clear(); 121  init(now); 122     for(register int i=0;i<=sz[now];i++)tp[i]=tp2[i]=cnt[i]=cnt2[i]=big[i]=0;Max=Max2=0; 123  sort(vv.begin(),vv.end()); 124  vv.erase(unique(vv.begin(),vv.end()),vv.end()); 125  init2(now); 126     summ+=Max2; 127     temp=Max2; 128  dfs(now); 129 } 130 int main() 131 { 132     int T; 133     scanf("%d",&T); 134     while(T--){ 135         int n,m; 136         scanf("%d%d",&n,&m); 137         for(register int i=1;i<=n;i++)head[i]=-1,dfn[i]=son[i]=vis[i]=Vis[i]=0,v[i].clear(),edg[i].clear(),eid[i].clear(); 138         etot=tot=Cnt=top=0; 139         for(register int i=1;i<=n;i++)scanf("%d",a+i); 140         for(register int i=1;i<=m;i++){ 141             int u,v; 142             scanf("%d%d",&u,&v); 143  addedge(v,u,i); 144  addedge(u,v,i); 145  } 146         for(register int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0); 147         for(register int i=1;i<=n;i++)v[id[i]].push_back(i); 148         summ=0; 149         for(register int i=1;i<=n;i++){ 150             for(register int j=head[i];~j;j=edge[j].next){ 151                 int u=id[i],to=id[edge[j].to]; 152                 if(u==to){ 153                     ans[edge[j].id]=0; 154                     continue; 155  } 156  edg[u].push_back(to);eid[u].push_back(edge[j].id); 157  } 158  } 159         for(register int i=1;i<=Cnt;i++) 160             if(!vis[i]) 161  solve(i); 162         for(register int i=1;i<=m;i++){ 163             if(i>1)putchar(' '); 164             printf("%d",ans[i]+summ); 165  } 166         puts(""); 167  } 168     return 0; 169 }
相关文章
相关标签/搜索