• 2021.5.8总结


    再次垫底
    开场发现A好像看过原题,是个单调栈,但是发现不太会做。
    然后看B发现好像是模板题。
    C也不太会做。
    回头想A,可以过中线分治后合法的点集就是单调栈。
    如果按照y降序排,则单调栈只有插入操作,容易维护。
    左边的限制想了一想可以线段树+二分。
    写完后就过了样例,然而手出的样例过不了。
    手出的样例过了后,写了个暴力对拍拍出了错。
    调了很久才拍上。。。。。
    然后看B,B也是很久没调出来,暴力都没时间写。。。。。
    交上去,A题被卡成暴力分,果然人傻常数大。
    然而我在LibreOJ上过了,就算100分吧
    最后只有100分。。。。。
    总结:问题出在B的点分治树好久没写过了,忘记了线段树要开2n个,所以没写出来。
    要复习一下点分治树的写法。

    题解:
    A:用经典的过中线分治。
    先离散化。
    一个左下端点合法的右上端点构成了单调栈中的单调点集:这个点集从左上到右下,(x)坐标单调递增,(y)坐标单调递减。
    按照(y)坐标倒序排序所有点,顺序枚举所有左边点,把右边(y)坐标大于当前点的右边点插入单调栈
    然而我们要考虑中线左边的限制。
    事实上,我们发现这个限制可以用线段树维护。
    建立线段树,维护区间最小值,初始所有元素为(inf)
    扫到第(i)个点时,先查询把([x,md])的最小值(v)
    发现当前点向上到(v-1)都是合法的。
    由于单调栈中(x)递增,所以在单调栈上合法区间是连续的,可以二分。
    然后把(x)位置的值修改成中点。
    时间复杂度(O(nlog_2^2n))
    不知道为什么跑的这么慢,但是在LibreOJ上过了

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 200010
    #pragma GCC optimize(3) 
    int n,x[N],y[N],st[N],tp,ans;
    struct no{
    	int x,y;
    }a[N];
    struct st{
    	int a[N*5];
    	void mod(int o,int l,int r,int x,int y){
    		if(l==r){
    			a[o]=y;
    			return;
    		}
    		int md=(l+r)/2;
    		if(x<=md)
    			mod(o*2,l,md,x,y);
    		else
    			mod(o*2+1,md+1,r,x,y);
    		a[o]=min(a[o*2],a[o*2+1]);
    	}
    	int qu(int o,int l,int r,int x,int y){
    		if(r<x||y<l)
    			return 1e9;
    		if(x<=l&&r<=y)
    			return a[o];
    		int md=(l+r)/2;
    		return min(qu(o*2,l,md,x,y),qu(o*2+1,md+1,r,x,y));
    	}
    }ss;
    int operator <(no x,no y){
    	return x.y>y.y;
    }
    vector<no>v;
    void fz(int l,int r,vector<no>v){
    	if(l>=r)
    		return;
    	int md=(l+r)/2;
    	vector<no>v1,v2;
    	for(int i=0;i<v.size();i++){
    		no x=v[i];
    		if(x.x<=md)
    			v1.push_back(x);
    		else
    			v2.push_back(x);
    	}
    	tp=0;
    	int j=0;
    	for(int i=0;i<v1.size();i++){
    		no x=v1[i];
    		while(j!=v2.size()&&v2[j].y>x.y){
    			while(tp&&v2[st[tp]].x>v2[j].x)
    				tp--;
    			st[++tp]=j;
    			j++;
    		}
    		int v=ss.qu(1,1,n,x.x,md),l=1,r=tp,po=tp+1;
    		while(l<=r){
    			int md=(l+r)/2;
    			if(v2[st[md]].y<=v){
    				po=md;
    				r=md-1;
    			}
    			else
    				l=md+1;
    		}
    		ans+=tp-po+1;
    		ss.mod(1,1,n,x.x,x.y);
    	}
    	for(int i=0;i<v1.size();i++){
    		no x=v1[i];
    		ss.mod(1,1,n,x.x,1e9);
    	}
    	fz(l,md,v1);
    	fz(md+1,r,v2);
    }
    signed main(){
    	freopen("scarecrows.in","r",stdin);
    	freopen("scarecrows.out","w",stdout);
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld%lld",&a[i].x,&a[i].y);
    	for(int i=1;i<=n;i++)
    		ss.mod(1,1,n,i,1e9);
    	for(int i=1;i<=n;i++){
    		x[i]=a[i].x;
    		y[i]=a[i].y;
    	}
    	sort(x+1,x+n+1);
    	sort(y+1,y+n+1);
    	for(int i=1;i<=n;i++){
    		a[i].x=lower_bound(x+1,x+n+1,a[i].x)-x;
    		a[i].y=lower_bound(y+1,y+n+1,a[i].y)-y;
    	}
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;i++)
    		v.push_back(a[i]);
    	fz(1,n,v);
    	printf("%lld",ans);
    }
    

    B:模板题
    显然二分,问题转化成判定和一个点距离(leq d)的数是否(>val)
    这显然可以用点分治树解决,在每个节点上维护线段树即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 80010
    int n,h[N],w[N],v[N],nxt[N],ec,tp[N],sz[N],p[N],f[N],d[N],di[N],rt[N],lc[N*20],rc[N*20],ss[N*20],rr,ms[N],vi[N],ps,ff[N],ct;
    void add(int x,int y,int z){
    	v[++ec]=y;
    	w[ec]=z;
    	nxt[ec]=h[x];
    	h[x]=ec;
    }
    void d1(int x,int fa){
    	f[x]=fa;
    	sz[x]=1;
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa){
    			di[v[i]]=di[x]+w[i];
    			d[v[i]]=d[x]+1;
    			d1(v[i],x);
    			sz[x]+=sz[v[i]];
    			if(sz[v[i]]>sz[p[x]])
    				p[x]=v[i];
    		}
    }
    void d2(int x,int fa,int t){
    	tp[x]=t;
    	if(p[x])
    		d2(p[x],x,t);
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa&&v[i]!=p[x])
    			d2(v[i],x,v[i]);
    }
    int ll(int x,int y){
    	while(tp[x]!=tp[y]){
    		if(d[tp[x]]>d[tp[y]])
    			x=f[tp[x]];
    		else
    			y=f[tp[y]];
    	}
    	if(d[x]<d[y])
    		return x;
    	return y;
    }
    int dd(int x,int y){
    	return di[x]+di[y]-2*di[ll(x,y)];
    }
    void mod(int &o,int l,int r,int x,int y){
    	if(!o)
    		o=++ct;
    	ss[o]+=y;
    	if(l==r){
    		return;
    	}
    	int md=(l+r)/2;
    	if(x<=md)
    		mod(lc[o],l,md,x,y);
    	else
    		mod(rc[o],md+1,r,x,y);
    }
    int qq(int o,int l,int r,int x,int y){
    	if(r<x||y<l)
    		return 0;
    	if(x<=l&&r<=y)
    		return ss[o];
    	int md=(l+r)/2;
    	return qq(lc[o],l,md,x,y)+qq(rc[o],md+1,r,x,y);
    }
    void d4(int x,int fa){
    	sz[x]=1;
    	ms[x]=0;
    	for(int i=h[x];i;i=nxt[i])
    		if(!vi[v[i]]&&v[i]!=fa){
    			d4(v[i],x);
    			sz[x]+=sz[v[i]];
    		}
    }
    void gr(int x,int fa){
    	for(int i=h[x];i;i=nxt[i])
    		if(!vi[v[i]]&&v[i]!=fa){
    			gr(v[i],x);
    			ms[x]=max(ms[x],sz[v[i]]);
    		}
    	ms[x]=max(ms[x],ps-sz[x]);
    	if(ms[rr]>ms[x])
    		rr=x;
    }
    void d3(int x){
    	vi[x]=1;
    	for(int i=h[x];i;i=nxt[i])
    		if(!vi[v[i]]){
    			rr=0;
    			d4(v[i],x);
    			ps=sz[v[i]];
    			gr(v[i],x);
    			ff[rr]=x;
    			d3(rr);
    		}
    }
    void md(int x){
    	mod(rt[x],0,1e8,0,1);
    	int z=x;
    	while(ff[z]){
    		int d=dd(x,ff[z]);
    		mod(rt[ff[z]],0,1e8,d,1);
    		mod(rt[z+n],0,1e8,d,1);
    		z=ff[z];
    	}
    }
    int qu(int x,int va){
    	int y=x,ans=qq(rt[x],0,1e8,0,va);
    	while(ff[y]){
    		int d=dd(x,ff[y]);
    		if(va>=d)
    			ans+=qq(rt[ff[y]],0,1e8,0,va-d)-qq(rt[y+n],0,1e8,0,va-d);
    		y=ff[y];
    	}
    	return ans;
    }
    signed main(){
    	freopen("treekth.in","r",stdin);
    	freopen("treekth.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<n;i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    	}
    	ps=n;
    	d1(1,0);
    	d2(1,0,1);
    	memset(sz,0,sizeof(sz));
    	ms[0]=1e9;
    	d4(1,0);
    	gr(1,0);
    	d3(rr);
    	for(int i=1;i<=n;i++)
    		md(i);
    	for(int i=1;i<=n;i++){
    		int k;
    		scanf("%d",&k);
    		int l=0,r=1e8,ans=0;
    		while(l<=r){
    			int md=(l+r)/2;
    			if(qu(i,md)>=k){
    				ans=md;
    				r=md-1;
    			}
    			else
    				l=md+1;
    		}
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    oracle数据库查看修改字符集问题
    C/C++内存问题检查利器—Purify (五)
    C/C++内存问题检查利器—Purify (四)
    C/C++内存问题检查利器—Purify (三)
    Oracle 字符集的查看和修改
    C/C++内存问题检查利器—Purify (二)
    linux内存管理之活动内存区
    C/C++内存问题检查利器—Purify (一)
    postman——基础操作——API请求与响应——API响应
    postman——基础操作——History选项卡
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14744782.html
Copyright © 2020-2023  润新知