zoukankan      html  css  js  c++  java
  • 题解 P2879 【[USACO07JAN]区间统计Tallest Cow】

    P2879 【[USACO07JAN]区间统计Tallest Cow】

    其实我是刚学完哈希用标签搜哈希进来的,但打开一看觉得是个图论....
    看了题解才知道,确实和哈希没啥关系其实就是用map判重,然而我还是建图跑的拓扑
    看题解区只有一篇类似的做法还不是特详细,就赶紧来水一篇


    有n只牛,给你r条信息和最高的牛的高度,每条信息((a,b))表示(h_aleq 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
    ",h[i]);
    	return 0;
    }
    
    

    还有一个相似的题可以去写一下
    题解
    那个题是求一种可行方案,但其实就可以当最大值做

  • 相关阅读:
    用位运算实现十进制转换为二进制
    【Zhejiang University PATest】02-3. 求前缀表达式的值
    【Zhejiang University PATest】02-1. Reversing Linked List
    【Tsinghua OJ】隧道(Tunel)问题
    冒泡排序及其优化
    有序向量的查找算法
    【Tsinghua OJ】灯塔(LightHouse)问题
    有序向量的去重算法
    【Tsinghua OJ】祖玛(Zuma)问题
    倒水问题(《怎样解题》中的经典问题)
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12527397.html
Copyright © 2011-2022 走看看