2019.07.12【NOIP提高组】模拟 A 组

JZOJ 3360 BZOJ 3757 苹果树

题目


分析

树上莫队解决此题


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std;
const int N=50011;
struct node{int y,next;}e[N<<1],E[N<<2]; bool v[N];
struct rec{int l,r,la,lb,lca,rk;}q[N<<1];
int ls[N],hs[N],dfn[N<<1],ofn[N],ifn[N],a[N],n,m,k,K,block,root,cnt[N<<1],now,ans[N<<1],pos[N<<1],tot,Lca[N<<2],f[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void Add(int x,int y){
	e[++k]=(node){y,ls[x]},ls[x]=k,
	e[++k]=(node){x,ls[y]},ls[y]=k;
}
inline void ADD(int x,int y){
	E[++K]=(node){y,hs[x]},hs[x]=K,
	E[++K]=(node){x,hs[y]},hs[y]=K;
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void dfs(int x){
    f[x]=x,v[x]=0; dfn[ifn[x]=++tot]=x;
    for (rr int i=ls[x];i;i=e[i].next) if (v[e[i].y])
        dfs(e[i].y),f[e[i].y]=x; dfn[ofn[x]=++tot]=x;
    for (rr int i=hs[x];i;i=E[i].next)
        if (!v[E[i].y]) Lca[i]=Lca[i^1]=getf(E[i].y);
}
bool cmp(rec x,rec y){return (pos[x.l]^pos[y.l])?pos[x.l]<pos[y.l]:((pos[x.l]&1)?x.r<y.r:x.r>y.r);}
inline void add(int x){now+=++cnt[x]==1;}
inline void del(int x){now-=!(--cnt[x]);}
inline void update(int x){
	if (!x) return; v[x=dfn[x]]^=1;
	v[x]?add(a[x]):del(a[x]);
}
signed main(){
	n=iut(); m=iut(); block=sqrt(n<<1); k=K=1;
	for (rr int i=1;i<=n;++i) a[i]=iut(),v[i]=1;
	for (rr int i=1;i<=n;++i){
		rr int x=iut(),y=iut();
		if (!x||!y) root=x+y; else Add(x,y);
	}
	for (rr int i=1;i<=m;++i)
		q[i]=(rec){iut(),iut(),iut(),iut(),0,i},ADD(q[i].l,q[i].r);
	dfs(root); for (rr int i=1;i<=tot;++i) pos[i]=i/block+1;
	for (rr int i=1;i<=m;++i){
		q[i].lca=Lca[i<<1];
		if (q[i].lca==q[i].l||q[i].lca==q[i].r) q[i].lca=0;
		if (ifn[q[i].l]>ifn[q[i].r]) q[i].l^=q[i].r,q[i].r^=q[i].l,q[i].l^=q[i].r;
		ofn[q[i].r]<=ofn[q[i].l]?(q[i].l=ifn[q[i].l],q[i].r=ifn[q[i].r]):(q[i].l=ofn[q[i].l],q[i].r=ifn[q[i].r]);
	}
	sort(q+1,q+1+m,cmp);
	for (rr int i=1,L=0,R=0;i<=m;++i){
		for (;L<q[i].l;++L) update(L);
		for (;L>q[i].l;--L) update(L-1);
		for (;R>q[i].r;--R) update(R);
		for (;R<q[i].r;++R) update(R+1);
		if (q[i].lca) add(a[q[i].lca]);
		(cnt[q[i].la]&&cnt[q[i].lb]&&q[i].la!=q[i].lb)?(ans[q[i].rk]=now-1):(ans[q[i].rk]=now);
		if (q[i].lca) del(a[q[i].lca]);
	}
	for (rr int i=1;i<=m;++i) print(ans[i]),putchar(10);
	return 0;
}

JZOJ 3362 数数(分块打表鬼才题)

JZOJ 3397 洛谷 4556 雨天的尾巴

题目


分析

树上差分,线段树自底向上合并,然而洛谷95分不知所措


代码

#include <cstdio>
#include <cctype>
#define rr register
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int p=136303,N=100011;
struct node{int y,next;}e[N<<1],E[N<<1]; int w[p<<5],lson[p<<5],rson[p<<5];
struct rec{int u,v,z,lca;}q[N]; bool v[N];
int k=1,K=1,ls[N],hs[N],hash[p+1],f[N],fat[N],dep[N],tot,Lca[N<<1],ans[N],n,m;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y){
	e[++k]=(node){y,ls[x]},ls[x]=k,
	e[++k]=(node){x,ls[y]},ls[y]=k;
}
inline void Add(int x,int y){
	E[++K]=(node){y,hs[x]},hs[x]=K,
	E[++K]=(node){x,hs[y]},hs[y]=K;
}
inline signed locate(int x){
	rr int now=x%p;
	while (hash[now]&&hash[now]!=x) now=now%p+1;
	hash[now]=x; return now; 
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void init(int x){
    f[x]=x,v[x]=0,dep[x]=dep[fat[x]]+1;
    for (rr int i=ls[x];i;i=e[i].next) if (v[e[i].y])
        fat[e[i].y]=x,init(e[i].y),f[e[i].y]=x;
    for (rr int i=hs[x];i;i=E[i].next)
        if (!v[E[i].y]) Lca[i]=Lca[i^1]=getf(E[i].y);
}
inline void update(int x,int l,int r,int pos,int y){
	if (l==r) {w[x]+=y; return;}
	rr int mid=(l+r)>>1;
	if (pos<=mid){
		if (!lson[x]) lson[x]=++tot;
		update(lson[x],l,mid,pos,y);
	}else{
		if (!rson[x]) rson[x]=++tot;
		update(rson[x],mid+1,r,pos,y);
	}
	w[x]=max(w[lson[x]],w[rson[x]]);
}
inline void merge(int x,int last,int l,int r){
	if (l==r) {w[x]+=w[last]; return;}
	rr int mid=(l+r)>>1;
	if (lson[last]){
	    if (!lson[x]) lson[x]=lson[last];
	        else merge(lson[x],lson[last],l,mid);
    }
	if (rson[last]){
	    if (!rson[x]) rson[x]=rson[last];
	        else merge(rson[x],rson[last],mid+1,r);
    }
	w[x]=max(w[lson[x]],w[rson[x]]);
}
inline signed query(int x,int l,int r){
	if (l==r) return l;
	rr int mid=(l+r)>>1;
	if (w[lson[x]]>=w[rson[x]]) return query(lson[x],l,mid);
	    else return query(rson[x],mid+1,r);
}
inline void dfs(int x){
	v[x]=1;
	for (rr int i=ls[x];i;i=e[i].next)
	if (!v[e[i].y])
		dfs(e[i].y),merge(x,e[i].y,1,p);
	ans[x]=query(x,1,p);
}
signed main(){
	n=iut(); m=iut(); v[n]=1;
	for (rr int i=1;i<n;++i) add(iut(),iut()),v[i]=1;
	for (rr int i=1;i<=m;++i) q[i]=(rec){iut(),iut(),locate(iut()),0},Add(q[i].u,q[i].v);
	init(1); tot=n;
	for (rr int i=1;i<=m;++i){
		q[i].lca=Lca[i<<1]; if (dep[q[i].u]<dep[q[i].v]) q[i].u^=q[i].v,q[i].v^=q[i].u,q[i].u^=q[i].v;
		update(q[i].u,1,p,q[i].z,1),update(fat[q[i].lca],1,p,q[i].z,-1);
		if (q[i].lca==q[i].v) continue;
		update(q[i].v,1,p,q[i].z,1),update(q[i].lca,1,p,q[i].z,-1);
	}
	dfs(1);
	for (rr int i=1;i<=n;++i) print(hash[ans[i]]),putchar(10);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值