2.15模拟总结

前言

day11
期望:40+60+30=130
实际:40+0+30=70
rnk16

挂大分了。。
T2树边不加双向:60->0。
这什么伞兵bug啊!
整体状态也不太好,T2死磕无果。
T1看出正解结果写不出来拉插,乐。

题目解析

T1 网格序列(grid)

一开始看就不太想做的一个题。
因为对自己计数方面的能力还是不太自信。。。
还是喜欢树算法awa。
死磕T2N年后回来发现这个题有点纸老虎,拉插一下不就能过吗awa
然后…拉插柿子长啥样来着…
然后就for循环40分跑路了。

关键性质:一个序列合法,当且仅当行最大值的最大值等于列最大值的最大值
有了这个就不难列出答案的式子了:
a n s = ∑ i = 1 k ( i n − ( i − 1 ) n ) ( i m − ( i − 1 ) m ) ans=\sum_{i=1}^k(i^n-(i-1)^n)(i^m-(i-1)^m) ans=i=1k(in(i1)n)(im(i1)m)
这个东西显然是一个 n + m + 1 n+m+1 n+m+1 次的多项式。
直接连续选点快速插值即可 O ( n ) O(n) O(n) 求单点值。
求函数值的时候快速幂会炸,需要线性筛把 x n , x m x^n,x^m xn,xm 这两个东西当成积性函数筛出来(还是完全积性的呢!
然后就做完了。
确实是不太难的一道题,唉。

T2 交换游戏(exchange)

今日死因了属于是。
一直在想dfs序转二维数点问题,但是那样的话二维线段树直接就带上两个log了。
然后就一直在寻找各种优化到方法,后来整了一个差分加二维线段树合并的神奇科技拿掉了一个log,却带上了18倍常数。
呵呵,还不如个log。

正解感觉和NOI那道轻重边异曲同工,都是利用染色来进行题意的转化。
题意从另一个角度来看就是,一棵树一条边的两端点在另一棵树上形成的链之间的边是需要在考虑范围的。
然后用染色满足反过来的限制,dsu on tree 维护。
确实巧妙。

T3 树的删除(delete)

别说这个题我还真想到LCT了。
但是我也就只看出操作1可以当成换根,对于维护排名还是很茫然。
按照题解的思路,这个“链”可以恰好用类似access维护虚实边的方式维护。
确实不太好想到…但是既然觉得是LCT其实应该从那个算法反过来出发想想的。

感叹出题人真是用心良苦。

代码

T1

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=2e6+100;
const int M=1e6+100;
const int mod=998244353;

int n,m,k;

inline ll ksm(ll x,ll k){
	ll res(1);
	while(k){
		if(k&1) res=res*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return res;
}

ll nmi[N],mmi[N];
int vis[N],prime[N],tot;
void init(){
	nmi[1]=mmi[1]=1;
	for(int i=2,o=n+m+2;i<=o;i++){
		if(!vis[i]){
			prime[++tot]=i;
			nmi[i]=ksm(i,n);
			mmi[i]=ksm(i,m);
		}
		for(int j=1;j<=tot&&prime[j]<=o/i;j++){
			int now=prime[j];
			nmi[now*i]=nmi[now]*nmi[i]%mod;
			mmi[now*i]=mmi[now]*mmi[i]%mod;
			vis[now*i]=1;
			if(i%now==0) break;
		}
	}
	return;
}
ll f[N];
ll jc[N],ni[N],pre[N],suf[N];
ll lagrange(int n,ll *y,int k){
	//if(k<=n) return y[k];
	jc[0]=1;
	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
	ni[n]=ksm(jc[n],mod-2);
	for(int i=n-1;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;
	pre[0]=1;
	for(int i=1;i<=n;i++) pre[i]=pre[i-1]*(k-i+mod)%mod;
	suf[n+1]=1;
	for(int i=n;i>=1;i--) suf[i]=suf[i+1]*(k-i+mod)%mod;
	ll ans(0);
	for(int i=1;i<=n;i++){
		ll add=y[i]*pre[i-1]%mod*suf[i+1]%mod*ni[i-1]%mod*ni[n-i]%mod;
		//printf("i=%d add=%lld y=%lld pre=%lld suf=%lld ni=%lld %lld\n",i,add,y[i],pre[i-1],suf[i+1],ni[i-1],ni[n-i]);
		if((n-i)&1) ans=(ans+mod-add)%mod;
		else ans=(ans+add)%mod;
	}
	return ans;
}

signed main(){
	freopen("grid.in","r",stdin);
	freopen("grid.out","w",stdout);
	n=read();m=read();k=read();
	init();
	int o=n+m+2;
	for(int i=1;i<=o;i++){
		f[i]=(f[i-1]+(nmi[i]-nmi[i-1]+mod)*(mmi[i]-mmi[i-1]+mod))%mod;
	}
	printf("%lld\n",lagrange(o,f,k));
	return 0;
}
/*
*/

T2

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=2e5+100;
const int M=1e6+100;
const int mod=998244353;

int n,m,k;
bool jd=0;

#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
struct node{
	int lc,rc,sum;
}tr[N<<2];
node merge(node a,node b){
	if(!a.sum) return b;
	else if(!b.sum) return a;
	else return (node){a.lc,b.rc,a.sum+b.sum-(a.rc==b.lc)};
}
int laz[N<<2];
inline void tag(int k){
	tr[k].lc=tr[k].rc=0;tr[k].sum=1;
	laz[k]=0;
}
inline void pushdown(int k){
	if(laz[k]==-1) return;
	laz[k]=-1;tag(ls);tag(rs);
	return;
}
inline void pushup(int k){
	tr[k]=merge(tr[ls],tr[rs]);return;
}
void change(int k,int l,int r,int p,int w){
	if(l==r){
		tr[k].lc=tr[k].rc=w;tr[k].sum=1;
		return;
	}
	pushdown(k);
	if(p<=mid) change(ls,l,mid,p,w);
	else change(rs,mid+1,r,p,w);
	pushup(k);
}
node ask(int k,int l,int r,int x,int y){
	if(x>y) return (node){-1,-1,0};
	if(x<=l&&r<=y) return tr[k];
	pushdown(k);
	if(y<=mid) return ask(ls,l,mid,x,y);
	else if(x>mid) return ask(rs,mid+1,r,x,y);
	else return merge(ask(ls,l,mid,x,y),ask(rs,mid+1,r,x,y));
}
struct tree2{
	vector<int>v[N];
	void addline(int x,int y){
		v[x].push_back(y);v[y].push_back(x);
	}
	int hson[N],siz[N],dep[N],top[N],tim,fa[N],dfn[N],pos[N];
	void dfs1(int x,int f){
		siz[x]=1;dep[x]=dep[f]+1;
		fa[x]=f;
		for(int to:v[x]){
			if(to==f) continue;
			dfs1(to,x);
			siz[x]+=siz[to];
			if(siz[to]>siz[hson[x]]) hson[x]=to;	
		}
		return;
	}
	void dfs2(int x,int tp){
		top[x]=tp;
		dfn[++tim]=x;pos[x]=tim;
		if(hson[x]) dfs2(hson[x],tp);
		for(int to:v[x]){
			if(to==fa[x]||to==hson[x]) continue;
			dfs2(to,to);
		}
		return;
	}
	inline void add(int x){
		if(jd) printf("  add:%d\n",x);
		change(1,1,n,pos[x],1);return;
	}
	inline int Lca(int x,int y){
		while(top[x]!=top[y]){
			if(dep[top[x]]<dep[top[y]]) swap(x,y);
			x=fa[top[x]];
		}
		if(dep[x]<dep[y]) swap(x,y);
		return y;
	}
	inline node find(int x,int anc,int op){
		if(jd) printf("find: x=%d anc=%d op=%d\n",x,anc,op);
		node res=(node){-1,-1,0};
		while(top[x]!=top[anc]){
			res=merge(ask(1,1,n,pos[top[x]],pos[x]),res);
			if(jd){
				printf("  merge: %d %d (%d %d %d)\n",
				top[x],x,res.lc,res.rc,res.sum);
			}
			x=fa[top[x]];
		}
		res=merge(ask(1,1,n,pos[anc]+op,pos[x]),res);
		if(jd){
			node o=ask(1,1,n,pos[anc]+op,pos[x]);
			printf("  o: (%d %d %d)\n",o.lc,o.rc,o.sum);
			printf("  merge: %d %d (%d %d %d)\n",
			anc,x,res.lc,res.rc,res.sum);
		}
		return res;
	}
	inline int query(int x,int y){
		int lca=Lca(x,y);
		node u=find(x,lca,0),v=find(y,lca,1);
		if(jd){
			printf("query: (%d %d) lca=%d u:(%d %d %d) v:(%d %d %d)\n",
		x,y,lca,u.lc,u.rc,u.sum,v.lc,v.rc,v.sum);
		}
		return u.sum+v.sum-(u.lc==v.lc);
	}
}t2;
int ans[N],u[N],v[N];
struct tree1{
	vector<int>v[N];
	void addline(int x,int y){
		v[x].push_back(y);v[y].push_back(x);
	}
	int hson[N],siz[N],dep[N],top[N],tim,fa[N],dfn[N],pos[N];
	void dfs1(int x,int f){
		siz[x]=1;dep[x]=dep[f]+1;
		fa[x]=f;
		for(int to:v[x]){
			if(to==f) continue;
			dfs1(to,x);
			siz[x]+=siz[to];
			if(siz[to]>siz[hson[x]]) hson[x]=to;	
		}
		return;
	}
	void dfs2(int x,int tp){
		top[x]=tp;
		dfn[++tim]=x;pos[x]=tim;
		if(hson[x]) dfs2(hson[x],tp);
		for(int to:v[x]){
			if(to==fa[x]||to==hson[x]) continue;
			dfs2(to,to);
		}
		return;
	}
	void solve(int x,int kep){
		for(int to:v[x]){
			if(to==fa[x]||to==hson[x]) continue;
			solve(to,0);
		}
		if(hson[x]) solve(hson[x],1);
		t2.add(x);
		for(int to:v[x]){
			if(to==fa[x]||to==hson[x]) continue;
			for(int i=pos[to];i<=pos[to]+siz[to]-1;i++){
				int now=dfn[i];
				t2.add(now);
			}
		}
		if(fa[x]) ans[x]=t2.query(x,fa[x]);
		if(!kep){
			tag(1);
			if(jd) printf("clear\n\n");
		}
		return;
	}
}t1;

signed main(){
	freopen("exchange.in","r",stdin);
	freopen("exchange.out","w",stdout);
	n=read();
	for(int i=1;i<n;i++){
		u[i]=read(),v[i]=read();
		t1.addline(u[i],v[i]);
	}
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		t2.addline(x,y);
	}
	t2.dfs1(1,0);t2.dfs2(1,1);
	t1.dfs1(1,0);t1.dfs2(1,1);
	t1.solve(1,0);
	for(int i=1;i<n;i++){
		if(t1.fa[v[i]]==u[i]) swap(u[i],v[i]);
		printf("%d ",ans[u[i]]-1);
	}
	return 0;
}
/*
4
1 2
1 3
1 4
1 2
2 3
3 4
*/

T3

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=4e5+100;
const int M=1e6+100;
const int mod=998244353;

int n,m,k;
bool jd=0;

int mx,s[N];
inline void add(int p,int w){
	if(jd) printf("    val=%d\n",p);
	for(;p<=mx;p+=p&-p) s[p]+=w;
}
inline int ask(int p){
	int res(0);
	for(;p;p-=p&-p) res+=s[p];
	return res;
}

int tr[N][2],f[N],siz[N],bot[N],top[N],rev[N],val[N];
void print(){
	for(int i=1;i<=n;i++) printf("i=%d ls=%d rs=%d fa=%d siz=%d bot=%d top=%d\n",
	i,tr[i][0],tr[i][1],f[i],siz[i],bot[i],top[i]);
	puts("");
}
inline bool nroot(int x){
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
inline bool which(int x){
	return tr[f[x]][1]==x;
}
inline void pushup(int x){
	if(x){
		siz[x]=siz[tr[x][0]]+siz[tr[x][1]]+1;
		bot[x]=tr[x][1]?bot[tr[x][1]]:x;
		top[x]=tr[x][0]?top[tr[x][0]]:x;
	}
}
inline void Rev(int x){
	if(x){
		swap(tr[x][0],tr[x][1]);
		swap(bot[x],top[x]);
		rev[x]^=1;
	}
}
inline void pushdown(int x){
	if(rev[x]){
		rev[x]=0;
		Rev(tr[x][0]);Rev(tr[x][1]);
	}
}
inline void rotate(int x){
	int fa=f[x],gfa=f[fa];
	int d=which(x),son=tr[x][d^1];
	f[x]=gfa;if(nroot(fa)) tr[gfa][which(fa)]=x;
	f[fa]=x;tr[x][d^1]=fa;
	if(son){f[son]=fa;}tr[fa][d]=son;
	pushup(fa);pushup(x);
}
int zhan[N];
inline void splay(int x){
	assert(x);
	int top(0),y(x);
	zhan[++top]=x;
	while(nroot(y)) zhan[++top]=y=f[y];
	while(top) pushdown(zhan[top--]);
	for(int fa;fa=f[x],nroot(x);rotate(x)){
		if(nroot(fa)) which(fa)==which(x)?rotate(fa):rotate(x);
	}
	return;
}
int now;
void access(int x,int op=1){
	//assert(x);
	if(jd) printf("\naccess: %d\n",x);
	int ori=x;
	for(int y(0);x;y=x,x=f[x]){
		assert(x);
		splay(x);
		if(jd) printf("  del: %d siz=%d\n",x,siz[x]);
		add(val[bot[x]],-siz[x]);
		int o=tr[x][1];
		if(o){			
			//splay(o);
			//printf("  o=%d bot=%d siz=%d\n",o,bot[o],siz[o]);
			if(jd) printf("  add: %d siz=%d\n",o,siz[o]);
			add(val[bot[o]],siz[o]);
		}
		//splay(x);
		tr[x][1]=y;
		pushup(x);
	}
	splay(ori);
	if(op) val[ori]=++now;
	//assert(now==bot[now]);
	if(jd) printf("  add: %d siz=%d\n",ori,siz[ori]);
	add(val[op?top[ori]:bot[ori]],siz[ori]);
	if(jd) puts("");
}
void makeroot(int x){
	access(x);splay(x);Rev(x);
}
vector<int>v[N];
void dfs(int x,int fa){
	f[x]=fa;
	for(int to:v[x]){
		if(to!=fa) dfs(to,x);
	}
	return;
}
inline int rnk(int x){
	splay(x);
	int o=ask(val[bot[x]]-1);
	if(jd) printf("o=%d bot=%d siz=%d\n",o,bot[x],siz[tr[x][1]]);
	o+=siz[tr[x][1]];
	return o+1;
}
char ss[100];
signed main(){
	freopen("delete.in","r",stdin);
	freopen("delete.out","w",stdout);
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	n=read();m=read();
	mx=n+m;now=n;
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		v[x].push_back(y);v[y].push_back(x);
	}
	dfs(n,0);
	for(int i=1;i<=n;i++){
		val[i]=i;bot[i]=top[i]=i;siz[i]=1;
		add(val[i],1);
	}
	for(int i=1;i<=n;i++){
		access(i,0);//print();
	}
	for(int i=1;i<=m;i++){
		int op=read(),x=read();
		if(op==1){
			//val[x]=++now;
			makeroot(x);
		}
		else printf("%d\n",rnk(x));
		if(jd) printf("op=%d x=%d\n",op,x);
		if(jd) print();
	}
	return 0;
}
/*
4
1 2
1 3
1 4
1 2
2 3
3 4
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值