zoukankan      html  css  js  c++  java
  • HUT 线段树练习 部分题解

    F-poj 2886

    这题去年月神给我们14级的抓过。然而比较偏数学。

    题意大概是n个小朋友围成一圈,每个小朋友手里都有一张卡片,卡片上有个数字a[i]。

    从第k个小朋友开始,第k个小朋友出圈,然后让他的左手方向的第a[k]个小朋友出圈。然后这个小朋友又根据规则让另一个小朋友出圈。

    第p个出圈的小朋友拿到的糖果数目为p的因子个数,问谁拿到了最多的糖果

    如果我们从1到n,逐个判断它的因子数目有多少个,效率非常低。其实我们可以通过规律直接dfs出小于等于n的,因子个数最多的数

    因为要使因子个数尽量的多,该数应该满足如下性质,即可以表示为一系列连续质数的积,形如n=2^x1*3^x2*5^x3......

    于是我们根据这个思路进行dfs。然后我们就得到是第几个出圈的人拿到最多的糖果啦。

    之后我们要用线段树,求得拿到最多糖果的人是谁。

    线段树维护区间当前的人数,然后把查询左手方向的第a[k]个小朋友,转化为查询剩余数组的第k的小朋友(取相对位置),就能直接在线段树中查询了

    这里有关于反素数比较详细的介绍http://blog.csdn.net/ACdreamers/article/details/25049767

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=500008;
    int p[16]={2,3,5,7,11,13,17,19,23,29,31,37}; 
    int mx,nx;
    void dfs(int num,int x,int y,int lim)
    {
    	if(num>=9) 	return;
    	if(mx<x)
    	{
    		mx=x;
    		nx=y;
    	}
    	if(mx==x&&nx>y)
    		nx=y; 
    	int i;
    	for(i=1;i<=10;i++)
    	{
    		if(lim<y*p[num])	break; 
    		y*=p[num];
    		dfs(num+1,x*(i+1),y,lim);
    	}
    }		 
    struct fuck{
    	int x;
    	char s[15];
    }f[maxn]; 
    int a[maxn<<2]; 
    void build(int x,int y,int c)
    {
    	if(x==y)
    	{
    	 	a[c]=1;
    		 return;
    	}
    	int mid=(x+y)>>1;
    	build(x,mid,c<<1);
    	build(mid+1,y,c<<1|1);
    	a[c]=a[c<<1]+a[c<<1|1];
    }
    int update(int m,int x,int y,int c)
    {
    	 a[c]--;
    	if(x==y)
    	{
    	  	return x;
    	}
    	int mid=(x+y)>>1;
    	if(m<=a[c<<1])	return update(m,x,mid,c<<1);
    	else	return update(m-a[c<<1],mid+1,y,c<<1|1);
    }
    int main()
    {
    	int i,j,n,m;
    	while(scanf("%d%d",&n,&m)==2)
    	{
    		mx=nx=1;
    		dfs(0,1,1,n);
    		for(i=1;i<=n;i++)
    		 	scanf("%s%d",f[i].s,&f[i].x);
    		build(1,n,1); 
    		int k=n;
    		int shit;
    		for(i=1;i<=nx;i++)
    		{
    			k--;
    			shit=update(m,1,n,1); 
    			if(k<=0) 	break;
    			if(f[shit].x>0) 
    				m=(m-1+f[shit].x-1)%k+1;
    			else
    				m=((m+f[shit].x-1)%k+k)%k+1; 
    		}
    		printf("%s %d
    ",f[shit].s,mx); 
    	}
    	return 0;
    }
    

     H - Mayor's posters

    找一找可以发现别人转载的杭电老队长博客,里面有这题的详细介绍,关于离散化也有详细的讲解

    http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html

    I-hdu 1540 Tunnel Warfare

    有可以看做一条线的村庄互相用地道连接。敌人会破坏一些村庄。八路军可以修好前一个被破坏的村庄。询问第k个村庄直接或间接连接了多少个村子。

    区间合并问题。我的做法直接开两颗线段树。一颗存区间内最左边的,没有被破坏的村庄编号。一颗存区间内最右边的,没有被破坏的村庄编号,查询两次,将其相加即是答案。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxn=50008;
    const int INF=0x7f7f7f7f;
    int a[maxn<<4];
    int b[maxn<<4];
    int st[maxn];
    int n;
    void build(int x,int y,int c)
    {
    	if(x==y)
    	{
    		a[c]=n+1;
    		b[c]=0;
    		return;
    	}
    	int mid=(x+y)>>1;
    	build(x,mid,c<<1);
    	build(mid+1,y,c<<1|1);
    	a[c]=min(a[c<<1],a[c<<1|1]);
    	b[c]=max(b[c<<1],b[c<<1|1]);
    }
    void update(int sx,int sy,int x,int y,int c)
    {
    	if(x==y)
    	{
    		if(sy==0)
    		{
    			b[c]=a[c]=x;
    		}
    		else
    		{
    			b[c]=0;a[c]=n+1;
    		}
    		return;
    	}
    	int mid=(x+y)>>1;
    	if(sx<=mid)	update(sx,sy,x,mid,c<<1);
    	else	update(sx,sy,mid+1,y,c<<1|1);
    	a[c]=min(a[c<<1],a[c<<1|1]);
    	b[c]=max(b[c<<1],b[c<<1|1]);
    }
    int yquery(int sx,int sy,int x,int y,int c)
    {
    	if(sx<=x&&y<=sy)
    	{
    		return a[c];
    	}
    	int mid=(x+y)>>1;
    	int ans=n+1;
    	if(sx<=mid)	ans=min(ans,yquery(sx,sy,x,mid,c<<1));
    	if(sy>mid)	ans=min(ans,yquery(sx,sy,mid+1,y,c<<1|1));
    	return ans;	
    }
    int xquery(int sx,int sy,int x,int y,int c)
    {
    	if(sx<=x&&y<=sy)
    	{
    		return b[c];
    	}
    	int mid=(x+y)>>1;
    	int ans=0;
    	if(sx<=mid)	ans=max(ans,xquery(sx,sy,x,mid,c<<1));
    	if(sy>mid)	ans=max(ans,xquery(sx,sy,mid+1,y,c<<1|1));
    	return ans;	
    }
    bool query(int sx,int x,int y,int c)
    {
    	if(x==y)
    	{
    		if(a[c]==x)	return true;
    		return false;
    	}
    	int mid=(x+y)>>1;
    	if(sx<=mid)	return query(sx,x,mid,c<<1);
    	else	return query(sx,mid+1,y,c<<1|1);
    }
    int main()
    {
    	int i,j,m;
    	char s[5];
    	while(scanf("%d%d",&n,&m)==2)
    	{
    		build(1,n,1);
    		int u;
    		int top=0;
    		while(m--)
    		{
    			scanf("%s",s);
    			if(s[0]=='R')
    			{
    				update(st[--top],1,1,n,1);
    			}
    			else
    			{
    				scanf("%d",&u);
    				if(s[0]=='D')
    				{
    					update(u,0,1,n,1);
    					st[top++]=u;
    				}
    				else
    				{
    					int bitch;
    					if(query(u,1,n,1)) bitch=0;
    					else
    					{
    						bitch=1;
    						if(u>1)
    						bitch+=(u-xquery(1,u-1,1,n,1)-1);
    						if(u<n)
    						bitch+=(yquery(u+1,n,1,n,1)-u-1);
    					}
    					printf("%d
    ",bitch);
    				}
    			}
    		 } 
    	}
    	return 0;
    }
    

     J-light oj 1120

    扫描线问题需要会离散化,区间更新。而且这里的区间更新非常灵活,不是pushdown,而是pushup。根据需要解锁不同姿势。。。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll __int64
    const int maxn=30008;
    struct fuck{
    	int x,y,u,v;
    	int idx;
    	int w;
    	bool operator<(const fuck &a)	const
    	{
    		return idx<a.idx;
    	}
    }f[maxn<<1];
    int tol;
    int re;
    int a[maxn<<1];
    int b[maxn<<1];
    ll st[maxn<<4];
    int lazy[maxn<<4];
    int shit[maxn];
    int bs(int x)
    {
    	int left,right;
    	left=1;right=re;
    	while(left<=right)
    	{
    		int mid=(left+right)>>1;
    		if(b[mid]<x)	left=mid+1;
    		else	right=mid-1;
    	}
    	return left;
    }
    void init()
    {
    	memset(st,0,sizeof(st));
    	memset(lazy,0,sizeof(lazy));
    }
    void pushup(int c,int x,int y)
    {
    	if(lazy[c])	st[c]=b[y+1]-b[x];
    	else if(x==y)	st[c]=0;
    	else	st[c]=st[c<<1]+st[c<<1|1];
    }
    void update(int sx,int sy,int w,int x,int y,int c)
    {
    	if(sx>sy)	return;
    	if(sx<=x&&y<=sy)
    	{
    		lazy[c]+=w;
    		pushup(c,x,y);
    		return; 
    	}
    	int mid=(x+y)>>1;
    	if(sx<=mid)	update(sx,sy,w,x,mid,c<<1);
    	if(sy>mid)	update(sx,sy,w,mid+1,y,c<<1|1);
    	pushup(c,x,y);
    	return;
    }
    int main()
    {
    	int i,j,t,n,m,x,y,sx,sy,u,v;
    	int cas=1;
    	scanf("%d",&t);
    	while(t--)
    	{
    		scanf("%d",&n);
    		tol=0;
    		for(i=1;i<=n;i++)
    		{
    			scanf("%d%d%d%d",&x,&y,&sx,&sy);
    			f[++tol].idx=x;f[tol].x=y;f[tol].y=sy;
    			a[tol]=y;f[tol].w=1;
    			f[++tol].idx=sx;f[tol].x=y;f[tol].y=sy;
    			a[tol]=sy;f[tol].w=-1;
    		}
    		sort(f+1,f+tol+1);
    		sort(a+1,a+tol+1);
    	//	printf("%d
    ",tol);
    		a[0]=-1;re=0;
    		for(i=1;i<=tol;i++)
    			if(a[i]!=a[i-1])
    				b[++re]=a[i];
    		ll sum=0;
    		init();
    		for(i=1;i<=tol;i++)
    		{
    			u=bs(f[i].x);
    			v=bs(f[i].y);
    			//printf("%d %d
    ",u,v);
    			if(i==1)
    			update(u,v-1,f[i].w,1,re,1);
    			else
    			{
    			//	printf("%d
    ",st[1]);
    				sum+=st[1]*((ll)f[i].idx-(ll)f[i-1].idx);
    				update(u,v-1,f[i].w,1,re,1);
    			}
    		}
    		printf("Case %d: %lld
    ",cas++,sum);
    	}
    	return 0;
    }
    

     L-uvalive 4730 kingdom

    大白薯上的题。抓这题是liji的主意。线段树+并查集。

    在二维坐标上有一系列的点,每个点代表一个城市。进行一系列的操作。一种操作是将两个城市相连接,互通的城市形成一个州。另一个操作是询问y直线一共穿过了多少州和城市

    用并查集维护州的相连情况,然后分类讨论,更新y轴的城市和州分布情况,又是区间更新加离散化orz。

    分类讨论其实很简单。你需要仔细想想,什么情况下点y的州数目和城市数目变化,什么情况不变化,按照思路更新即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define db double
    const int maxn=200008;
    struct poi{
    	int x,y;
    	int idx;
    	bool operator<(const poi &a)	const
    	{
    		return y<a.y;
    	}
    }f[maxn];
    int g[maxn];
    int rel[maxn];
    int a[maxn<<4],b[maxn<<4];
    int lazya[maxn<<4],lazyb[maxn<<4];
    struct fuck{
    	int next;
    	int x,y;
    	int w;
    }uni[maxn];
    void init(int n)
    {
    	memset(a,0,sizeof(a));
    	memset(b,0,sizeof(b));
    	memset(lazya,0,sizeof(lazya));
    	memset(lazyb,0,sizeof(lazyb));
    	for(int i=1;i<=n;i++)
    	{
    		uni[i].next=i;
    		uni[i].x=uni[i].y=rel[i];
    		uni[i].w=1;
    	}
    }
    int find(int u)
    {
    	if(u==uni[u].next)	return u;
    	return uni[u].next=find(uni[u].next);
    }
    void pushdowna(int c)
    {
    	if(lazya[c]==0)	return;
    	lazya[c<<1]+=lazya[c];
    	lazya[c<<1|1]+=lazya[c];
    	a[c<<1]+=lazya[c];
    	a[c<<1|1]+=lazya[c];
    	lazya[c]=0;
    }
    void pushdownb(int c)
    {
    	if(lazyb[c]==0)	return;
    	lazyb[c<<1]+=lazyb[c];
    	lazyb[c<<1|1]+=lazyb[c];
    	b[c<<1]+=lazyb[c];
    	b[c<<1|1]+=lazyb[c];
    	lazyb[c]=0;
    }
    void update(int sx,int sy,int w,int x,int y,int c)
    {
    	if(sx>sy)	return;
    	if(sx<=x&&y<=sy)
    	{
    		a[c]+=w;
    		lazya[c]+=w;
    		return;
    	}
    	pushdowna(c);
    	int mid=(x+y)>>1;
    	if(sx<=mid)	update(sx,sy,w,x,mid,c<<1);
    	if(mid<sy)	update(sx,sy,w,mid+1,y,c<<1|1);
    	return;
    }
    void updateb(int sx,int sy,int w,int x,int y,int c)
    {
    	if(sx>sy)	return;
    	if(sx<=x&&y<=sy)
    	{
    		b[c]+=w;
    		lazyb[c]+=w;
    		return;
    	}
    	pushdownb(c);
    	int mid=(x+y)>>1;
    	if(sx<=mid)	updateb(sx,sy,w,x,mid,c<<1);
    	if(mid<sy)	updateb(sx,sy,w,mid+1,y,c<<1|1);
    	return;
    }
    int bs(db shit,int n)
    {
    	int left,right;
    	left=1;right=n;
    	while(left<=right)
    	{
    		int mid=(left+right)>>1;
    		if(f[mid].y<shit)	left=mid+1;
    		else	right=mid-1; 
    	}
    	return left-1;
    }
    int query(int sx,int x,int y,int c)
    {
    	if(x==y)
    	{
    		return a[c];
    	}
    	pushdowna(c);
    	int mid=(x+y)>>1;
    	if(sx<=mid)	return query(sx,x,mid,c<<1);
    	else	return query(sx,mid+1,y,c<<1|1);
    }
    int queryb(int sx,int x,int y,int c)
    {
    	if(x==y)
    	{
    		return b[c];
    	}
    	pushdownb(c);
    	int mid=(x+y)>>1;
    	if(sx<=mid)	return queryb(sx,x,mid,c<<1);
    	else	return queryb(sx,mid+1,y,c<<1|1);
    }
    int main()
    {
    	int i,j,t,n,m,u,v,x,y;
    	scanf("%d",&t);
    	char s[10];
    	while(t--)
    	{
    		scanf("%d",&n);
    		for(i=1;i<=n;i++)
    		{
    			scanf("%d%d",&f[i].x,&f[i].y);
    			f[i].idx=i;
    		}
    		sort(f+1,f+1+n);
    		for(i=1;i<=n;i++)
    			g[f[i].idx]=i; 
    		int pre=-1,k=0;
    		for(i=1;i<=n;i++)
    		{
    			if(f[i].y!=pre)
    				rel[i]=++k;
    			else
    				rel[i]=k;
    			pre=f[i].y;
    		} 
    		init(n);
    		scanf("%d",&m);
    		while(m--)
    		{
    			scanf("%s",s);
    			if(s[0]=='r')
    			{
    				scanf("%d%d",&u,&v);
    				u++;v++;
    				u=g[u];v=g[v];
    				x=find(u);y=find(v); 
    				if(x!=y)
    				{
    					if(uni[x].y>uni[y].y){
    						int shit=x;x=y;y=shit;
    					}
    					if(uni[x].y<uni[y].x)
    					{
    						update(uni[x].y,uni[y].x-1,1,1,k,1);
    						updateb(uni[x].y,uni[y].x-1,uni[y].w+uni[x].w
    								,1,k,1);
    						updateb(uni[x].x,uni[x].y-1,uni[y].w,1,k,1);
    						updateb(uni[y].x,uni[y].y-1,uni[x].w,1,k,1);
    					}
    					else
    					{
    						update(max(uni[y].x,uni[x].x),
    								uni[x].y-1,-1,1,k,1);
    						updateb(uni[x].x,uni[y].x-1,uni[y].w,1,k,1);
    						updateb(uni[y].x,uni[x].x-1,uni[x].w,1,k,1);
    						updateb(uni[x].y,uni[y].y-1,uni[x].w,1,k,1);
    					}
    					uni[x].next=y;
    					uni[y].w+=uni[x].w;
    					uni[y].x=min(uni[x].x,uni[y].x);
    				}
    			}
    			else
    			{
    				db shit;
    				scanf("%lf",&shit);
    				if(shit<f[1].y)
    				{
    					printf("0 0
    ");
    					continue;
    				}
    				x=bs(shit,n);
    				x=rel[x];
    				int sx=query(x,1,k,1);
    				int sy=queryb(x,1,k,1);
    				printf("%d %d
    ",sx,sy);
    			 } 
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    第一阶段——站立会议总结DAY10
    第十二周学习进度条
    第一阶段——站立会议总结DAY09
    第一阶段——站立会议总结DAY08
    人机交互设计课下作业
    第一阶段——站立会议总结DAY07
    第一阶段——站立会议总结DAY06
    第一阶段——站立会议总结DAY05
    个人总结
    第二个冲刺期的第十天
  • 原文地址:https://www.cnblogs.com/bitch1319453/p/5353008.html
Copyright © 2011-2022 走看看