吐槽一下为什么绍兴一中出的题码量这么大
题意: 给你一个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;
}