hdu5756 2016 Multi-University Training Contest 3 Boss Bo 解题报告

吐槽一下为什么绍兴一中出的题码量这么大


题意: 给你一个n个点,以1为根的树,Q个询问,每次问你如果把若干个点的子树删掉,剩下的点里面,到P点的距离和,距离的最大值或问距离的最小值,如果点删完了,就输出-1。强制在线的,每次给你一个p,实际的P=(p+lastans)%n +1,lastans是上次的答案,如果是-1或第一组询问,lastans=0。



题解: 先处理出根节点1到每个点的距离,建一棵可持久化线段树维护和,最大值,最小值,然后从根节点向下,通过dfs序,对每个点子树里的点权-1,对不在子树里的点权+1,要用静态标记,不用貌似会被卡。

然后对于询问,在P点的主席树上询问删掉的点的子树之外的区间,因为删掉的点的总数不超过20万,所以不会超时。



code:

#pragma comment(linker, "/STACK:102400000,102400000")  
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define inf 99999999
using namespace std;

const int maxn = 101000;

struct edge
{
	int y,next;
}a[maxn<<1]; int len,first[maxn];
void insert( int x,int y )
{
	len++;
	a[len].y = y; 
	a[len].next = first[x]; first[x] = len;
}

struct tree
{
	int lc,rc,sum,max,min,c;
}tr[maxn*40]; int z;
int root[maxn];
int siz[maxn],s[maxn];
int sid[maxn],node[maxn],num;
int n,Q;

struct query
{
	int l,r;
}del[maxn]; int dlen;
bool cmp( query x,query y )
{
	return x.l == y.l ? x.r < y.r : x.l < y.l;
}

void clear( int x )
{
	tr[x].lc = tr[x].rc = tr[x].sum = tr[x].c = 0;
	tr[x].max = -inf;
	tr[x].min = inf;
}
void up( int x,int l,int r )
{
	int mid = (l+r)>>1, lc = tr[x].lc, rc = tr[x].rc;
	tr[x].sum = tr[lc].sum+tr[lc].c*(mid-l+1) 
			+ tr[rc].sum+tr[rc].c*(r-mid);
	tr[x].max = max( tr[lc].max+tr[lc].c,tr[rc].max+tr[rc].c );
	tr[x].min = min( tr[lc].min+tr[lc].c,tr[rc].min+tr[rc].c );
}
void dfs( int x,int f )
{
	siz[x] = 1;
	sid[x] = ++num;
	node[num] = x;
	for( int k=first[x];k;k=a[k].next )
	{
		if( a[k].y != f )
		{
			s[a[k].y] = s[x]+1;
			dfs( a[k].y,x );
			siz[x] += siz[a[k].y];
		}
	}
}
void build_tree( int &x,int l,int r )
{
	if( !x ) 
	{
		x = ++z;
		clear( x );
	}
	if( l == r )
	{
		tr[x].sum = tr[x].max = tr[x].min = s[node[l]];
		return ;
	}
	int mid = ( l+r )>>1;
	build_tree( tr[x].lc,l,mid );
	build_tree( tr[x].rc,mid+1,r );
	up( x,l,r );
}
void merge( int &x,int y,int l,int r )
{
	if( !y ) return ;
	if( !x )
	{
		x = y;
		return ;
	}
	tr[x].c += tr[y].c;
	if( l == r ) 
	{
		tr[x].max = max( tr[x].max, tr[y].max );
		tr[x].min = min( tr[x].min, tr[y].min );
		tr[x].sum += tr[y].sum;
		return ;
	}
	int mid = ( l+r )>>1;
	merge( tr[x].lc,tr[y].lc,l,mid );
	merge( tr[x].rc,tr[y].rc,mid+1,r );
	up( x,l,r );
	
}
void update( int &x,int l,int r,int lx,int rx,int c )
{
	if( !x )
	{
		x = ++z;
		clear( x );
	}
	if( lx <= l && r <= rx )
	{
		tr[x].c += c;
		return ;
	}
	int mid = ( l+r )>>1;
	if( rx <= mid ) update( tr[x].lc,l,mid,lx,rx,c );
	else if( lx > mid ) update( tr[x].rc,mid+1,r,lx,rx,c );
	else
	{
		update( tr[x].lc,l,mid,lx,mid,c );
		update( tr[x].rc,mid+1,r,mid+1,rx,c );
	}
}
void build( int x,int f )
{
	update( root[x],1,num,sid[x],sid[x]+siz[x]-1,-1 );
	update( root[x],1,num,1,sid[x]-1,1 );
	if( sid[x]+siz[x] <= num )
		update( root[x],1,num,sid[x]+siz[x],num,1 );
	merge( root[x],root[f],1,num );
	for( int k=first[x];k;k=a[k].next )
		if( a[k].y != f ) build( a[k].y,x );
}
int Q_Sum( int x,int l,int r,int lx,int rx,int c )
{
	c += tr[x].c;
	if( lx <= l && r <= rx ) return tr[x].sum + (r-l+1)*c;
	int mid = ( l+r )>>1;
	if( rx <= mid ) return Q_Sum( tr[x].lc,l,mid,lx,rx,c );
	else if( lx > mid ) return Q_Sum( tr[x].rc,mid+1,r,lx,rx,c );
	else return Q_Sum( tr[x].lc,l,mid,lx,mid,c )
			+ Q_Sum( tr[x].rc,mid+1,r,mid+1,rx,c );
}
int Q_Max( int x,int l,int r,int lx,int rx,int c )
{
	c += tr[x].c;
	if( lx <= l && r <= rx ) return tr[x].max+c;
	int mid = ( l+r )>>1;
	if( rx <= mid ) return Q_Max( tr[x].lc,l,mid,lx,rx,c );
	else if( lx > mid ) return Q_Max( tr[x].rc,mid+1,r,lx,rx,c );
	else return max( Q_Max( tr[x].lc,l,mid,lx,mid,c ) ,
					Q_Max( tr[x].rc,mid+1,r,mid+1,rx,c ) );
}
int Q_Min( int x,int l,int r,int lx,int rx,int c )
{
	c += tr[x].c;
	if( lx <= l && r <= rx ) return tr[x].min+c;
	int mid = ( l+r )>>1;
	if( rx <= mid ) return Q_Min( tr[x].lc,l,mid,lx,rx,c );
	else if( lx > mid ) return Q_Min( tr[x].rc,mid+1,r,lx,rx,c );
	else return min( Q_Min( tr[x].lc,l,mid,lx,mid,c ),
					Q_Min( tr[x].rc,mid+1,r,mid+1,rx,c ) );
}

int main()
{
	int x,y;
	clear( 0 );
	
	while( scanf("%d%d",&n,&Q) != EOF )
	{
		len = num = z = 0;
		for( int i=0;i<=n;i++ )
		{
			s[i] = first[i] = root[i] = 0;
		}
		
		for( int i=1;i<n;i++ )
		{
			scanf("%d%d",&x,&y);
			insert( x,y );
			insert( y,x );
		}
		dfs( 1,0 );
		build_tree( root[1],1,num );
		for( int k=first[1];k;k=a[k].next )
			build( a[k].y,1 );
		
		int lastans = 0;
		while( Q-- )
		{
			int k,p,ki,tmp;
			scanf("%d%d%d",&k,&p,&ki);
			if( lastans == -1 ) lastans = 0;
			p = ( p+lastans ) % n + 1;
			
			for( int i=0;i<k;i++ )
			{
				scanf("%d",&tmp);
				del[i].l = sid[tmp];
				del[i].r = sid[tmp]+siz[tmp]-1;
			}
			sort( del,del+k,cmp );
			dlen = 0; if( k == 0 ) del[0].l = del[0].r = 0;
			for( int i=1;i<k;i++ )
			{
				if( del[i].l <= del[dlen].r+1 )
				{
					del[dlen].r = max( del[dlen].r,del[i].r );
				}
				else del[++dlen] = del[i];
			}
			
			if( del[0].l == 1 && del[0].r == num ) lastans = -1;
			else if( ki == 1 )
			{
				lastans = 0;
				if( del[0].l>1 )
					lastans += Q_Sum( root[p],1,num,1,del[0].l-1,0 );
				for( int i=1;i<=dlen;i++ )
					lastans += Q_Sum( root[p],1,num,
								del[i-1].r+1,del[i].l-1,0 );
				if( del[dlen].r < num )
					lastans += Q_Sum( root[p],1,num,
								del[dlen].r+1,num,0 );
			}
			else if( ki == 2 )
			{
				lastans = inf;
				
				if( del[0].l>1 )
					lastans = min( lastans,
							Q_Min( root[p],1,num,1,del[0].l-1,0 ) );
							
				for( int i=1;i<=dlen;i++ )
					lastans = min( lastans,
					Q_Min( root[p],1,num,del[i-1].r+1,del[i].l-1,0 ) );
					
				if( del[dlen].r < num )
					lastans = min( lastans,
					Q_Min( root[p],1,num,del[dlen].r+1,num,0 ) );
			}
			else
			{
				lastans = -inf;
				
				if( del[0].l>1 )
					lastans = max( lastans,
							Q_Max( root[p],1,num,1,del[0].l-1,0 ) );
				
				for( int i=1;i<=dlen;i++ )
					lastans = max( lastans,
					Q_Max( root[p],1,num,del[i-1].r+1,del[i].l-1,0 ) );
				
				if( del[dlen].r < num )
					lastans = max( lastans,
					Q_Max( root[p],1,num,del[dlen].r+1,num,0 ) );
			}
			printf("%d\n",lastans);
		}
	}
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值