CF1805E 题解
题意
定义一棵树的 MAD 值为其出现次数大于等于两次的点权最大值。现在给出一棵树,对于每一条边,你要求出将其删除后形成的两棵新树的 MAD 值的最大值。
注意不是真正删掉边,询问间相互独立。
树有n个点( 2≤n≤10^5 )
点权 ( 1≤ai≤109 )
算法步骤
1 我们发现当同一种元素出现3次及以上,无论如何分割,MAD 都不会小于它。
2 对于出现次数等于两次的点权中最大的,只有割去他们唯一路径上的边才无法构成 MAD 值,割去其余边的答案都是 出现次数等于两次的点权中最大的。
3 考虑割去 出现次数等于两次的点权中最大的两点之间路径上的边。它们组成一条链,将不组成该链的点用并查集维护与他们最近相连的链上点构成的集合。
接着考虑次大 MAD 值候选,若两点在同一集合,割去链上各条边的答案都为它,若不在,我们可以收缩两个端点,求出连接他们的链上边,不连接他们的边对应答案就是次大候选值。
4 循环往复,链只会不断变短。
复杂度
瓶颈在于对点权排序O(nlogn)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N = 1e5+5; 5 int n,a[N]; 6 vector<int> g[N],dd[N]; 7 map <int,int> pc; 8 map <ll,int> ans; 9 map <int,int> mp; 10 map <int,int> lian; 11 int id; 12 int dow; 13 int b[N]; 14 int u[N],v[N]; 15 int nex[N]; 16 int fa[N]; 17 int gef(int x){ 18 if(x==fa[x])return x; 19 else return fa[x] = gef(fa[x]); 20 } 21 bool dfs(int ls,int v,int val){ 22 // cout << v<<" arri\n"; 23 bool f = 0; 24 for(int i=0;i<g[v].size();i++){ 25 int vv=g[v][i]; 26 if(vv==ls)continue; 27 if(dfs(v,vv,val))nex[v] =vv,f=1; 28 else fa[vv] = v; 29 30 } 31 // cout << f << "\n\n"; 32 //cout << val<<"\n\n"; 33 //if( v== 4)cout << dd[pc[val]][1]<<"\n\n"; 34 35 if( v == dd[pc[val]][1] || f)return true; 36 else ans[v*(1e5+1)+ls]=ans[ls*(1e5+1)+v]=val; 37 return false; 38 } 39 int len[N],l; 40 int main(){ 41 cin >> n; 42 for(int i = 1;i < n;i++){ 43 //int a,b; 44 cin >> u[i] >> v[i]; 45 g[v[i]].push_back(u[i]),g[u[i]].push_back(v[i]); 46 } 47 int maxx=0; 48 for(int i = 1;i <= n; i++){ 49 cin >> a[i]; 50 fa[i]=i; 51 b[i]=a[i]; 52 if(!mp[a[i]]){ 53 id++; 54 pc[a[i]]=id; 55 } 56 mp[a[i]]++; 57 if(mp[a[i]]>=3)dow=max(a[i],dow); 58 if(mp[a[i]]>=2)maxx=max(maxx,a[i]); 59 60 dd[pc[a[i]]].push_back(i); 61 } 62 sort(a+1,a+n+1); 63 for(int i = n;i >= 1; i--){ 64 if(a[i] <= dow)break; 65 if(mp[a[i]]<2)continue; 66 else { 67 dfs(-1,dd[pc[a[i]]][0],a[i]); 68 int uu = dd[pc[a[i]]][0]; 69 while(uu){ 70 len[++l]=uu; 71 lian[uu]=l; 72 uu=nex[uu]; 73 74 } 75 break; 76 } 77 78 } 79 // for(int i =1;i <=l;i++) 80 // cout << len[i]<<" "; 81 int lef = 1,rig = l; 82 for(int i = n;i >= 1; i--){ 83 if(a[i] <= dow)break; 84 if(mp[a[i]]<2)continue; 85 int uu = dd[pc[a[i]]][0],vv=dd[pc[a[i]]][1]; 86 uu = gef(uu),vv=gef(vv); 87 uu=lian[uu],vv=lian[vv]; 88 if(uu > vv)swap(uu,vv); 89 //if(a[i]==1)cout << uu <<" "<<vv<<"\n"; 90 for(int j = lef;j<uu;j++){ 91 fa[len[j]]=len[j+1]; 92 ans[len[j]*(1e5+1)+len[j+1]]=ans[len[j+1]*(1e5+1)+len[j]]=a[i]; 93 } 94 lef=uu; 95 for(int j = rig-1;j>=vv;j--){ 96 fa[len[j+1]]=len[j]; 97 ans[len[j]*(1e5+1)+len[j+1]]=ans[len[j+1]*(1e5+1)+len[j]]=a[i]; 98 } 99 rig=vv; 100 if(lef==rig)break; 101 } 102 for(int i = 1;i < n;i++){ 103 if(!ans[v[i]*(1e5+1)+u[i]])cout << dow<<"\n"; 104 else cout << ans[v[i]*(1e5+1)+u[i]]<<"\n"; 105 //g[v[i]].push_back(u[i]),g[u[i]].push_back(v[i]); 106 } 107 108 return 0; 109 }

浙公网安备 33010602011771号