zoukankan      html  css  js  c++  java
  • [HNOI2015][bzoj4009] 接水果 [整体二分+扫描线]

    题面

    传送门

    思路

    本题其实有在线做法......但是太难写了,退而求其次写了离线

    基本思路就是,考虑一个盘子以及它能接到的所有水果

    可以发现,这个水果的端点一定在这个盘子两端的“子树”内(加引号是因为可能是一条链顶端外面的“子树”)

    那么,可以把模型抽象成:盘子就是矩形,两个端点就是两个维度上的限制,而水果就是点

    一个水果可以被接住,当且仅当这个水果的点在某个盘子的矩形内部

    考虑盘子的不同情况:

    如果盘子是有一个折点的折链,那么两边的限制,就是两个端点的子树dfs序范围

    如果盘子是一条从下到上的链,那么这个矩形实际上是有两个的:

    假设链是(u,v),u是v的祖先,这条链上从u开始下一个点是x

    那么,其中一维的限制显然是$[dfn[v],last[v]]$,

    但是另一维上的限制实际上有两个拼起来:

    $[1,dfn[x]-1]$和$[last[x]+1,n]$

    这里实际上是得到了$u$外面的“子树”的dfs序范围

    我们把这些链拆成矩形,然后跑一个整体二分,每次二分每个水果被多少个矩形覆盖

    当前二分区间是$[l,r]$,如果$[l,mid]$中的覆盖矩形的数量大于要求的数量,就进入左边

    否则,要求的数量减去这个覆盖矩形数量,并进入右边

    这样总复杂度是$O(nlog^2n)$

    实现的时候,可以把矩形的两个维度中小的那个放在x,大的放在y,注意这里不要写错了

    Code

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cassert>
    #include<queue>
    #include<cmath>
    #define las DEEP_DARK_FANTASY
    #define lowbit(x) (x&(-x))
    #define mp make_pair
    using namespace std;
    namespace IO
    {
        const int __S=(1<<20)+5;char __buf[__S],*__H,*__T;
        inline char getc()
        {
            if(__H==__T) __T=(__H=__buf)+fread(__buf,1,__S,stdin);
            if(__H==__T) return -1;
    		return *__H++;
        }
        template <class __I>inline void read(__I &__x)
        {
            __x=0;int __fg=1;char __c=getc();
            while(!isdigit(__c)&&__c!='-') __c=getc();
            if(__c=='-') __fg=-1,__c=getc();
            while(isdigit(__c)) __x=__x*10+__c-'0',__c=getc();
            __x*=__fg;
        }
        inline void readd(double &__x)
        {
            __x=0;double __fg=1.0;char __c=getc();
            while(!isdigit(__c)&&__c!='-') __c=getc();
            if(__c=='-') __fg=-1.0,__c=getc();
            while(isdigit(__c)) __x=__x*10.0+__c-'0',__c=getc();
            if(__c!='.'){__x=__x*__fg;return;}else while(!isdigit(__c)) __c=getc();
            double __t=1e-1;while(isdigit(__c)) __x=__x+1.0*(__c-'0')*__t,__t=__t*0.1,__c=getc();
            __x=__x*__fg;
        }
        inline void reads(char *__s,int __x)
        {
            char __c=getc();int __tot=__x-1;
            while(__c<'a'||__c>'z') __c=getc();
            while(__c>='a'&&__c<='z') __s[++__tot]=__c,__c=getc();
            __s[++__tot]='';
        }
        char __obuf[__S],*__oS=__obuf,*__oT=__oS+__S-1,__c,__qu[55];int __qr;
        inline void flush(){fwrite(__obuf,1,__oS-__obuf,stdout);__oS=__obuf;}
        inline void putc(char __x){*__oS++ =__x;if(__oS==__oT) flush();}
        template <class __I>inline void print(__I __x)
        {
            if(!__x) putc('0');
            if(__x<0) putc('-'),__x=-__x;
            while(__x) __qu[++__qr]=__x%10+'0',__x/=10;
            while(__qr) putc(__qu[__qr--]);
        }
        inline void prints(const char *__s,const int __x)
        {
            int __len=strlen(__s+__x);
            for(int __i=__x;__i<__len+__x;__i++) putc(__s[__i]);
        }
        inline void printd(long double __x,int __d)
        {
            long long __t=(long long)floor(__x);print(__t);putc('.');__x-=(double)__t;
            while(__d--)
            {
                long double __y=__x*10.0;__x*=10.0;
                int __c=(int)floor(__y+1e-9);if(__c==10) __c--;
                putc(__c+'0');__x-=floor(__y);
            }
        }
        inline void el(){putc('
    ');}inline void sp(){putc(' ');}
    }using namespace IO;
    
    inline int read(){
    	int re=0,flag=1;char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    int n,m,k,first[40010],cnte,dfn[40010],las[40010],st[40010][20],dep[40010],clk;
    struct edge{
    	int to,next;
    }a[100010];
    inline void add(int u,int v){
    	a[++cnte]=(edge){v,first[u]};first[u]=cnte;
    	a[++cnte]=(edge){u,first[v]};first[v]=cnte;
    }
    void dfs(int u,int f){
    	int i,v;
    	st[u][0]=f;dep[u]=dep[f]+1;
    	dfn[u]=++clk;
    	for(i=first[u];~i;i=a[i].next){
    		v=a[i].to;if(v==f) continue;
    		dfs(v,u);
    	}
    	las[u]=clk;
    }
    void ST(){
    	int i,j;
    	for(j=1;j<=16;j++)
    		for(i=1;i<=n;i++)
    			st[i][j]=st[st[i][j-1]][j-1];
    }
    int getpre(int l,int r){
    	int i;
    	if(l==r) return l;
    	if(dep[l]>dep[r]) swap(l,r);
    	for(i=16;i>=0;i--) if(dep[st[r][i]]>dep[l]) r=st[r][i];
    	if(st[r][0]==l) return r;
    	else return 0;
    }
    struct mat{
    	int lx,rx,ly,ry,val,id;
    }p[100010];int cntp;
    inline bool cmp(mat l,mat r){
    	return l.val<r.val;
    }
    struct fru{
    	int x,y,id,ans,k;
    }f[40010];
    struct ele{
    	int l,r,id;
    };
    namespace BIT{
    	int a[100010];
    	void Add(int x,int val){
    		for(;x<=n;x+=lowbit(x)) a[x]+=val;
    	}
    	void add(int l,int r,int val){
    		Add(l,val);Add(r+1,-val);
    	}
    	int sum(int x){
    		int re=0;
    		for(;x>0;x-=lowbit(x)) re+=a[x];
    		return re;
    	}
    }
    queue<ele>q;
    vector<int>s,le,ri;
    vector<pair<int,int> >t;
    inline bool cmps(int l,int r){
    	return f[l].x<f[r].x;
    }
    inline bool cmpt(pair<int,int>l,pair<int,int>r){
    	int vl,vr;
    	if(l.second) vl=p[l.first].rx;
    	else vl=p[l.first].lx;
    	if(r.second) vr=p[r.first].rx;
    	else vr=p[r.first].lx;
    	return vl<vr;
    }
    void solve(){
    	ele cur;int i,l,r,mid,j,tmp,tval;
    	for(i=1;i<=k;i++) q.push((ele){1,cntp,i});
    
    	while(!q.empty()){
    		cur=q.front();q.pop();
    		if(cur.l==cur.r){f[cur.id].ans=p[cur.l].val;continue;}
    		l=cur.l;
    		r=cur.r;
    		s.clear();
    		s.push_back(cur.id);
    		mid=(l+r)>>1;t.clear();
    
    		while(!q.empty()&&q.front().l==l&&q.front().r==r){
    			s.push_back(q.front().id);
    			q.pop();
    		}
    		sort(s.begin(),s.end(),cmps);
    
    		for(i=l;i<=mid;i++){
    			t.push_back(mp(i,0));
    			t.push_back(mp(i,1));
    		}
    		sort(t.begin(),t.end(),cmpt);
    
    		j=-1;le.clear();ri.clear();
    		for(i=0;i<t.size();i++){
    			if(t[i].second) tmp=p[t[i].first].rx;
    			else tmp=p[t[i].first].lx;
    
    			while((j<((int)s.size()-1))&&(f[s[j+1]].x<tmp)){
    				j++;tval=BIT::sum(f[s[j]].y);
    				if(tval<f[s[j]].k){
    					f[s[j]].k-=tval;
    					ri.push_back(s[j]);
    				}
    				else{
    					le.push_back(s[j]);
    				}
    			}
    			if(t[i].second) BIT::add(p[t[i].first].ly,p[t[i].first].ry,-1);
    			else BIT::add(p[t[i].first].ly,p[t[i].first].ry,1);
    		}
    		while(j<((int)s.size()-1)){
    			j++;tval=BIT::sum(f[s[j]].y);
    			if(tval<f[s[j]].k){
    				f[s[j]].k-=tval;
    				ri.push_back(s[j]);
    			}
    			else{
    				le.push_back(s[j]);
    			}
    		}
    		for(auto lef:le) q.push((ele){l,mid,lef});
    		for(auto rig:ri) q.push((ele){mid+1,r,rig});
    	}
    }
    int main(){
    	read(n);read(m);read(k);
    	int i,t1,t2,t3,tmp;
    	memset(first,-1,sizeof(first));
    	for(i=1;i<n;i++){
    		read(t1);read(t2);
    		add(t1,t2);
    	}
    	dfs(1,0);ST();
    	for(i=1;i<=m;i++){
    		read(t1);read(t2);read(t3);
    		if(dep[t2]<dep[t1]) swap(t1,t2);
    		tmp=getpre(t1,t2);
    		if(tmp){
    			if(dfn[tmp]>1) p[++cntp]=(mat){1,dfn[tmp]-1+1,dfn[t2],las[t2],t3,i};
    			if(las[tmp]<n) p[++cntp]=(mat){dfn[t2],las[t2]+1,las[tmp]+1,n,t3,i};
    		}
    		else{
    			if(dfn[t2]<dfn[t1]) swap(t1,t2);
    			p[++cntp]=(mat){dfn[t1],las[t1]+1,dfn[t2],las[t2],t3,i};
    		}
    	}
    	
    	sort(p+1,p+cntp+1,cmp);
    
    	for(i=1;i<=k;i++){
    		read(t1);read(t2);read(t3);
    		if(dfn[t1]>dfn[t2]) swap(t1,t2);
    		f[i]=(fru){dfn[t1],dfn[t2],i,0,t3};
    	}
    	solve();
    	for(i=1;i<=k;i++) print(f[i].ans),el();
    	flush();
    }
    
  • 相关阅读:
    markdown grammar
    vs the address of offline package
    步步为营-66-Socket通信
    步步为营-65-线程小例子
    线程使用中常见的错误-“System.InvalidOperationException”线程间操作无效: 从不是创建控件“ ”的线程访问它。
    步步为营-64-进程&线程
    步步为营-63-Asp.net-get与post
    步步为营-62-Excel的导入和导出
    步步为营-61-拼音组件
    步步为营-60-代码生成器
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9800900.html
Copyright © 2011-2022 走看看