题解:P2266 爱的供养
fish_love_cat · · 题解
?kruskal 重构树秒了。
直接建重构树,倍增找到子树大小合法的最深点,答案找到了。
时间复杂度单 log,做完了。
我没读错题吧?写一下等会挂了就好笑了。
绷不住了,重构树的非叶子是虚点,警钟长鸣。
#include<bits/stdc++.h>
#define ll long long
#define N 750005
using namespace std;
int kuai;
int a[N],b[N<<1];
int n,m,Q;
int ID(int x,int y){
return (x-1)*m+y;
}
struct fish{
int u,v,w;
};
bool cmp(fish x,fish y){
return x.w<y.w;
}
vector<fish>ev;
int fa[N<<1];
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
vector<int>ve[N<<1];
ll f[N<<1];
int l[N<<1];
int r[N<<1];
int dfn[N<<1],dfnn;
int ta[N<<1],ta2[N<<1];
int fath[25][N<<1];
int siz[N<<1];
void dfs(int x){
dfn[x]=++dfnn;
ta2[dfnn]=ta[dfnn]=b[x];
l[x]=dfnn;
for(int i:ve[x])dfs(i),fath[0][i]=x,siz[x]+=siz[i];
r[x]=dfnn;
}
int ans[N<<1];
struct que{
int l,r,t,id;
};
struct update{
int id,x,y;
};
bool pmc(que x,que y){
if(x.l/kuai!=y.l/kuai)return x.l<y.l;
if(x.r/kuai!=y.r/kuai)return x.r<y.r;
return x.t<y.t;
}
int t[N];
int flc;
void ins(int x){
if(x<=0)return;
if(t[x]==0)flc++;
t[x]++;
}
void del(int x){
if(x<=0)return;
t[x]--;
if(t[x]==0)flc--;
}
int L=1,R=0,T=0;
void Upd(update x){
if(x.id>=L&&x.id<=R){
del(x.x);
ins(x.y);
}
ta[x.id]=x.y;
}
signed main(){
int twt;
cin>>n>>m>>twt;
int nn=n,mm=m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int id=ID(i,j);
cin>>a[id];
siz[id]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int id=ID(i,j);
b[id]=id;
}
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
ev.push_back({ID(i,j),ID(i,j+1),abs(a[ID(i,j)]-a[ID(i,j+1)])});
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
ev.push_back({ID(i,j),ID(i+1,j),abs(a[ID(i,j)]-a[ID(i+1,j)])});
sort(ev.begin(),ev.end(),cmp);
n=n*m;
for(int i=1;i<=n+n;i++)fa[i]=i;
for(int i=n+1;i<=n+n;i++)b[i]=-1;
for(fish i:ev){
if(find(i.u)==find(i.v))continue;
i.u=find(i.u);
i.v=find(i.v);
n++;
ve[n].push_back(i.u);
ve[n].push_back(i.v);
fa[i.u]=n;
fa[i.v]=n;
f[n]=i.w;
}
dfs(n);
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
fath[i][j]=fath[i-1][fath[i-1][j]];
ll ret=0;
n=nn,m=mm;
for(int x=1;x<=n;x++)
for(int y=1;y<=m;y++){
int op;
cin>>op;
if(!op)continue;
int id=ID(x,y);
for(int j=20;j>=0;j--)
if(fath[j][id]&&siz[fath[j][id]]<twt)
id=fath[j][id];
if(siz[id]<twt)
id=fath[0][id];
ret+=f[id];
}
cout<<ret;
return 0;
}
// 那已经是很久之前发生的事了。
// 理由什么的已经无关紧要了吧。
// 人是不会为了无关紧要的事情拼上性命的。
// 老夫只是在守护妻子最爱的村子。
// 我妻子是人类。
// 老夫只不过是一直在遵守着那个在遥远的过去许下的承诺罢了。
// 很可笑,对吧。
// 这么多年来,老夫只不过是一直在遵守着与死者的承诺罢了。
// 是这样呢。
// 不过,我觉得那个女性,一定会因为您一直守护着与她的约定,而由衷的感到开心。
// 辛美尔,你是一位优秀的勇者。
// 想必一定可以击败魔王吧。
// 老夫的妻子也一直期盼着魔王被击败,和平时代能够到来的那一天。
// 名为辛美尔的伟大勇者的回忆,就由老夫带去未来吧。
什么你问为啥代码里有一车和一位的东西?问就是,从双倍经验粘的。
什么,你问的是注释?那你猜。