题解 P2879 【[USACO07JAN]区间统计Tallest Cow】
P2879 【[USACO07JAN]区间统计Tallest Cow】
其实我是刚学完哈希用标签搜哈希进来的,但打开一看觉得是个图论....
看了题解才知道,确实和哈希没啥关系其实就是用map判重,然而我还是建图跑的拓扑
看题解区只有一篇类似的做法还不是特详细,就赶紧来水一篇
有n只牛,给你r条信息和最高的牛的高度,每条信息\((a,b)\)表示\(h_a\leq h_b\),且a,b之间所有牛高度比\(h_a\)低,求每头牛最大高度
建图时从高的牛连向低的牛,小于的情况边权为1(高度至少要低1)
对于小于等于的情况当然要让它取等(因为要求最大高度),所以边权应为0
拓扑时,对于边\((u,v)\),让\(h[v]=min(h[v],h[u]-w[i])\),其中\(w[i]\)是当前边边权
然后发现这样建图边数是\(Rn\)的,所以考虑用线段树优化
在线段树中的点是从\(n+1\)开始编号,对应我代码里的nn
最后注意线段树中的边边权也要为0就行了
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,nn,maxh,m;
int h[30006],fir[30006],in[30006];
int nex[200006],to[200006],w[200006],edge;
struct tr{
tr *ls,*rs;
int id;
}dizhi[20006],*root=&dizhi[0];
int tot;
inline void add(int u,int v,int tmp){
to[++edge]=v;w[edge]=tmp;
nex[edge]=fir[u];fir[u]=edge;
}
void build(tr *tree,int l,int r){
if(l==r) return tree->id=l,void();
int mid=(l+r)>>1;
tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
build(tree->ls,l,mid);build(tree->rs,mid+1,r);
tree->id=++nn;
add(tree->id,tree->ls->id,0);add(tree->id,tree->rs->id,0);
in[tree->ls->id]++;in[tree->rs->id]++;
}
void addtree(tr *tree,int l,int r,int ql,int qr,int u){
if(ql<=l&&r<=qr) return add(u,tree->id,1),in[tree->id]++,void();
int mid=(l+r)>>1;
if(ql<=mid) addtree(tree->ls,l,mid,ql,qr,u);
if(qr>mid) addtree(tree->rs,mid+1,r,ql,qr,u);
}
std::queue<int>q;
inline void topo(){
for(reg int i=1;i<=nn;i++){
h[i]=maxh;
if(!in[i]) q.push(i);
}
while(!q.empty()){
reg int u=q.front();q.pop();
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
h[v]=std::min(h[v],h[u]-w[i]);
if(!--in[v]) q.push(v);
}
}
}
int main(){
n=nn=read();read();maxh=read();m=read();//那个输入的i并没有什么用,直接read()掉就行,代码里的m就是题里的R
reg int a,b;
build(root,1,n);
while(m--){
a=read();b=read();
add(b,a,0);in[a]++;
reg int minn=std::min(a,b),maxx=std::max(a,b);
if(minn<maxx-1) addtree(root,1,n,minn+1,maxx-1,a);//a,b之间至少有一头牛
}
topo();
for(reg int i=1;i<=n;i++) std::printf("%d\n",h[i]);
return 0;
}