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 }
相關文章
相關標籤/搜索