zoukankan      html  css  js  c++  java
  • ●洛谷P3242 [HNOI2015]接水果

    题链:

    https://www.luogu.org/problemnew/show/P3242

    题解:

    整体二分,扫描线+树状数组。
    详细的题解:http://blog.csdn.net/thy_asdf/article/details/50363672
    得到各个盘子影响的矩形区域后,
    那么我们就是要对每个询问代表的点查询覆盖了它的权值第k小的的那个矩形。
    首先有一个简化版的问题,
    就是查询改点被覆盖了多少次。可以用扫描线+树状数组做。
    然后对于现在询问的第k小权值,
    我们就可以二分答案,即二分一个权值mid,
    然后判断是否这些权值小于mid的矩形可以覆盖该点至少k次,
    使得话,缩小r,否则扩大l范围。
    由于有多个询问,且分别做二分的话过程是一样的,所以可以整体二分。

    另外,还可以对当前扫描线上的东西建立树套树,
    外面是权值线段树,里面套的是区间线段树(方便区间修改,单点查询),也可以求出第k小的权值。
    如果想看具体实现的话,推荐服用这位博主的代码:http://blog.csdn.net/make_it_for_good/article/details/52985365

    再另外,好像还可以树上莫队+平衡树做,但是我太弱了,忘了树上莫队,就没写了。
    但是我感觉如果用莫队的话,如果数据故意把水果和盘子的左端点放到同一个位置附近,
    同时程序的分块又恰好把这些位置分在了同一个块,
    可能会被卡成n^2的。

    代码:

    #include<bits/stdc++.h>
    #define MAXN 160008
    #define rint register int
    using namespace std;
    int N,P,Q,snt;
    int ANS[MAXN],fa[MAXN][18],deep[MAXN],be[MAXN],en[MAXN];
    struct Edge{
    	int ent;
    	int to[MAXN],nxt[MAXN],head[MAXN];
    	Edge(){ent=2;}
    	void Adde(int u,int v){
    		to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
    	}
    }E;
    struct Plate{
    	int x1,x2,y1,y2,val;
    }S[MAXN];
    struct info{
    	int x,yl,yr,val,id;
    }A[MAXN],T[MAXN];
    bool cmp1(const Plate &_A,const Plate &_B){
    	return _A.val<_B.val;
    }
    bool cmp2(const info &_A,const info &_B){
    	return _A.x<_B.x||(_A.x==_B.x&&_A.id<_B.id);
    }
    struct BIT{
    	int val[MAXN],n;
    	void Reset(int _n){n=_n;}
    	int Lowbit(int x){return x&(-x);}
    	void Modify(int l,int r,int x){//区间修改
    		if(l>r) return;
    		for(rint i=l;i<=n;i+=Lowbit(i)) val[i]+=x;
    		for(rint i=r+1;i<=n;i+=Lowbit(i)) val[i]-=x;
    	}
    	int Query(int p,int ret=0){//查询覆盖次数 
    		for(rint i=p;i>=1;i-=Lowbit(i)) ret+=val[i];
    		return ret;
    	}
    }DT;
    void dfs(int u,int dad){
    	static int cnt; ++cnt;
    	be[u]=cnt; fa[u][0]=dad;
    	for(int k=1;k<18;k++)
    		fa[u][k]=fa[fa[u][k-1]][k-1];
    	for(int e=E.head[u];e;e=E.nxt[e]){
    		int v=E.to[e]; if(v==dad) continue;
    		deep[v]=deep[u]+1; dfs(v,u);
    	}
    	en[u]=cnt;
    }
    int jump(int x,int h){
    	for(int k=17;k>=0;k--) 
    		if(h>=(1<<k)) x=fa[x][k],h-=(1<<k);
    	return x;
    }
    info inssegment(const Plate &rtm,int k){
    	static int x1,x2,y1,y2,v;
    	x1=rtm.x1; x2=rtm.x2; y1=rtm.y1; y2=rtm.y2; v=rtm.val;
    	assert(x1<=x2);
    	if(k==1) return (info){x1,y1,y2,v,-1};
    	else return (info){x2+1,y1,y2,v,-2};
    }
    void solve(int sl,int sr,int ql,int qr){
    	static int sum[MAXN];
    	if(ql>qr) return;
    	if(sl==sr){
    		for(int i=ql;i<=qr;i++) ANS[A[i].id]=S[sl].val;
    		return;
    	}
    	int mid=(sl+sr)>>1,tnt=0,qlnt=ql-1,qrnt=0;
    	for(int i=sl;i<=mid;i++) T[++tnt]=inssegment(S[i],1),T[++tnt]=inssegment(S[i],2);
    	for(int i=ql;i<=qr;i++) T[++tnt]=A[i];
    	sort(T+1,T+tnt+1,cmp2);
    	for(int i=1;i<=tnt;i++){
    		if(T[i].id<0) DT.Modify(T[i].yl,T[i].yr,T[i].id==-1?1:-1);
    		else sum[T[i].id]=DT.Query(T[i].yl);
    	}
    	for(int i=1;i<=tnt;i++){
    		if(T[i].id<0) DT.Modify(T[i].yl,T[i].yr,T[i].id==-1?-1:1);
    		else{
    			if(sum[T[i].id]>=T[i].val) A[++qlnt]=T[i];
    			else T[i].val-=sum[T[i].id],T[++qrnt]=T[i];
    		}
    	}
    	for(int i=1;i<=qrnt;i++) A[i+qlnt]=T[i];		
    	solve(sl,mid,ql,qlnt);
    	solve(mid+1,sr,qlnt+1,qr);
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin>>N>>P>>Q;
    	for(int i=1,a,b;i<N;i++)
    		cin>>a>>b,E.Adde(a,b),E.Adde(b,a);
    	dfs(1,0); DT.Reset(N);
    	for(int i=1,x,y,v,t;i<=P;i++){
    		cin>>x>>y>>v;
    		if(be[x]>be[y]) swap(x,y); 
    		if(be[x]<=be[y]&&en[x]>=en[y]){
    			t=jump(y,deep[y]-deep[x]-1);
    			S[++snt]=(Plate){1,be[t]-1,be[y],en[y],v};
    			if(en[t]+1<=N) S[++snt]=(Plate){be[y],en[y],en[t]+1,N,v};
    		}
    		else S[++snt]=(Plate){be[x],en[x],be[y],en[y],v};
    	}
    	sort(S+1,S+snt+1,cmp1);
    	for(int i=1,x,y,k;i<=Q;i++){
    		cin>>x>>y>>k;
    		if(be[x]>be[y]) swap(x,y);
    		A[i]=(info){be[x],be[y],0,k,i};
    		//在构建的二维平面里,x点对应的下标不是x,而是be[x]
    		//wa了一次,就是因为上面的那行代码写成了:
    		//A[i]=(info){x,y,0,k,i};
    	}
    	solve(1,snt,1,Q);
    	for(int i=1;i<=Q;i++) cout<<ANS[i]<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    log4net GetLogger(source).IsInfoEnabled = false
    nginx配置
    mysql数据库备份
    按序号批量更新某个字段
    MySql 执行 DELETE/UPDATE时,报 Error Code: 1175错误
    ef学习记录
    vue-cli3实行路径联想
    GitHub分支创建及合并
    Git本地分支和远程分支关联
    uniapp(三)
  • 原文地址:https://www.cnblogs.com/zj75211/p/8541628.html
Copyright © 2011-2022 走看看