noip模拟83

今天的4个题有3个数据是错的,就nm离谱,冲了T1的正解,T2部分分少取了个模数少了30。。。

最后100+30+30+0

T1

两种做法,一种是直接维护区间加和以及区间乘机%大质数,另一种直接维护多重集hash,数剖实现一下就行了

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=2.5e5+5;
struct edge{int to,nxt;}e[maxn<<1];int a[maxn],val[maxn];
int head[maxn],cnt,num,fa[maxn],siz[maxn],top[maxn],son[maxn],dfn[maxn],dep[maxn],n,m;
int jc[maxn],jc2[maxn],q;
inline void add(int x,int y)
{
	e[++num]=(edge){y,head[x]};head[x]=num;
	e[++num]=(edge){x,head[y]};head[y]=num;
}
inline void dfs1(int x,int f)
{
	siz[x]=1;son[x]=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==f) continue;
		dep[y]=dep[x]+1;fa[y]=x;
		dfs1(y,x);siz[x]+=siz[y];
		if(siz[y]>=siz[son[x]]) son[x]=y;
	}
}
inline void dfs2(int x,int tp)
{
	dfn[x]=++cnt;top[x]=tp;val[cnt]=a[x];	
	if(!son[x])return; dfs2(son[x],tp);
	for(int i=head[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}
inline void clear()
{	
	num=0;cnt=0;
	memset(head,0,sizeof(head));
}
const int mod=998244353;
const int mod2=1e9+7;
struct seg_tree{
	#define lid id<<1
	#define rid id<<1|1
	struct tree{int mx,mn;ll sum;int cj,cj2;}tr[maxn<<2];
	inline tree add(tree a,tree b)
	{
		a.mn=min(a.mn,b.mn);
		a.mx=max(a.mx,b.mx);
		a.sum=a.sum+b.sum;
		a.cj=1ll*a.cj*b.cj%mod;
		a.cj2=1ll*a.cj2*b.cj2%mod2;
		return a;
	}
	inline void build(int id,int l,int r)
	{
		if(l==r) return tr[id]=(tree){val[l],val[l],val[l],val[l],val[l]},void();
		int mid=(l+r)>>1; build(lid,l,mid);build(rid,mid+1,r);
		tr[id]=add(tr[lid],tr[rid]);
	}
	inline void update(int id,int l,int r,int pos,int val)
	{
		if(l==r)return tr[id]=(tree){val,val,val,val,val},void();
		int mid=(l+r)>>1;
		if(pos<=mid) update(lid,l,mid,pos,val);
		else update(rid,mid+1,r,pos,val);
		tr[id]=add(tr[lid],tr[rid]);
	}
	inline tree query(int id,int l,int r,int L,int R)
	{
		if(l>=L&&r<=R) return tr[id];
		int mid=(l+r)>>1;tree ans=(tree){0,1000000000,0,1,1};
		if(L<=mid) ans=add(ans,query(lid,l,mid,L,R));
		if(R>mid) ans=add(ans,query(rid,mid+1,r,L,R));
		return ans;
	}
	inline bool check(int x,int y)
	{
		tree ans=(tree){0,1000000000,0,1,1};
		if(!x||!y){return false;}
		int nw=0;
		while(top[x]!=top[y])
		{
			if(dep[top[x]]<dep[top[y]])swap(x,y);
			ans=add(ans,query(1,1,n,dfn[top[x]],dfn[x]));
			nw+=dfn[x]-dfn[top[x]]+1;x=fa[top[x]];
		}
		if(dep[x]<dep[y]) ans=add(ans,query(1,1,n,dfn[x],dfn[y])),nw+=dfn[y]-dfn[x]+1;
		else ans=add(ans,query(1,1,n,dfn[y],dfn[x])),nw+=dfn[x]-dfn[y]+1;
		if(ans.mx!=nw) return false; if(ans.mn!=1) return false;
		if(ans.sum!=1ll*(nw)*(nw+1)/2)return false;
		if(ans.cj!=jc[nw]) return false;
		if(ans.cj2!=jc2[nw]) return false;
		return true;
	}
}T;
signed main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int t=read();jc[0]=jc2[0]=1;
	for(int i=1;i<=maxn-1;i++)
	{
		jc[i]=1ll*jc[i-1]*i%mod;
		jc2[i]=1ll*jc2[i-1]*i%mod2;
	}
	while(t--)
	{
		clear();n=read();q=read();
		for(int i=1;i<=n;i++) a[i]=read();
		for(int i=1;i<n;i++) add(read(),read());
		dfs1(1,0);dfs2(1,1);T.build(1,1,n);
		while(q--)
		{
			int type=read();
			if(type==1)
			{
				int x=read(),y=read();
				if(T.check(x,y)) puts("Yes");
				else puts("No");
			}
			else
			{
				int x=read(),y=read();
				T.update(1,1,n,dfn[x],y);
			}
		}
	}
}

T2 连任

一个比较经典的线段树分治模板,在线段树上维护一个可撤销并查集,线段树建立在时间轴上,然后一遍dfs就好了

#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e5+5,mod=1e9+7;
int fa[maxn],siz[maxn],m,n,ans=1,inv[maxn];
inline int ksm(int x,int y)
{
	int res=1;x=x%mod;
	for(;y;y>>=1){if(y&1)res=res*x%mod;x=x*x%mod;}
	return res;
}
map<int,int>mp[maxn];
struct data{int x,y,l,r;}p[maxn];
struct node{int x,siz;};
stack<node>stk;
inline int getfa(int x){while(fa[x]!=x) x=fa[x];return x;}
inline void merge(int x,int y)
{
	int fx=getfa(x),fy=getfa(y);
	if(fx==fy) return ;
	if(siz[fx]>siz[fy]) swap(fx,fy);
	stk.push((node){fx,siz[fx]});
	ans=ans*inv[siz[fx]]%mod*inv[siz[fy]]%mod*(siz[fx]+siz[fy])%mod;
	siz[fy]=siz[fy]+siz[fx];fa[fx]=fy;
}
inline void del(int sze)
{
	while(stk.size()>sze) 
	{
		node a=stk.top();
		ans=ans*inv[siz[fa[a.x]]]%mod*a.siz%mod*(siz[fa[a.x]]-a.siz)%mod;
		siz[fa[a.x]]-=a.siz; fa[a.x]=a.x; stk.pop();
	}
}
vector<int>vec[maxn<<2];
inline void insert(int id,int l,int r,int ll,int rr,int x)
{
	if(l>=ll&&r<=rr) 
	{
		vec[id].push_back(x);
		return ;
	}
	int mid=(l+r)>>1;
	if(ll<=mid) insert(lid,l,mid,ll,rr,x);
	if(rr>mid) insert(rid,mid+1,r,ll,rr,x);
}
inline void dfs(int id,int l,int r)
{
	int nw=stk.size();
	for(auto y:vec[id]) merge(p[y].x,p[y].y);
	if(l==r){printf("%lld\n",ans);del(nw);return;}
	int mid=(l+r)>>1;
	dfs(lid,l,mid);dfs(rid,mid+1,r);
	del(nw);
}
signed main()
{
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
	for(int i=1;i<=n;i++) inv[i]=ksm(i,mod-2);
	for(int i=1;i<=m;i++)
	{
		int type=read(),x=read(),y=read();
		if(type==1)
		{
			p[i].x=x;p[i].y=y; p[i].l=i;
			mp[x][y]=mp[y][x]=i;p[i].r=m;
		}
		else
		{
			int id=mp[x][y]; p[id].r=i-1;
		}
	}
	for(int i=1;i<=m;i++) if(p[i].x)
	insert(1,1,m,p[i].l,p[i].r,i);
	dfs(1,1,m);
}

T3 排列

NB题,学会了处理纯三维偏序统计的\(O(nlog(n))\)做法

考虑分别对其中的两维处理二维偏序,那么如果其中两个点是三维偏序,那么肯定会被计算三次,如果只有两维满足偏序就只会被计算一次

那么我们设这三次处理的二维偏序的和为\(M\),那么三维偏序的个数为\((M-n*(n-1)/2)/2\)

我觉得这是比较显然的,就是两个点肯定满足不是二维偏序就是三维偏序

那么减去所有的数对就相当于减去了只有二维和三维的三分之一

有-1的计算一下贡献就行了

#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e6+5;
const int mod=998244353;
struct node{int a,b,c;}p[maxn];
int n,a[maxn],b[maxn],vis[maxn];
struct tree{
	#define lowbit(x) (x&(-x))
	int c[maxn];
	inline void update(int x,int val){for(;x<=n;x+=lowbit(x))c[x]+=val;}
	inline int query(int x)
	{int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
	inline void clear(){memset(c,0,sizeof(c));}
}T,T2;
inline int ksm(int x,int y)
{
	int res=1;x=x%mod;
	for(;y;y>>=1){if(y&1)res=1ll*res*x%mod;x=1ll*x*x%mod;}
	return res;
}
bool cmp2(node a,node b){return a.b<b.b;}
signed main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	n=read();int all=0;
	for(int i=1;i<=n;i++)a[i]=read(),p[i].a=i,p[i].b=a[i];
	for(int i=1;i<=n;i++)
	{
		b[i]=read(),p[i].c=b[i];
		if(b[i]==-1) all++;
	}
	for(int i=1;i<=n;i++)if(b[i]!=-1) vis[b[i]]=1;
	for(int i=1;i<=n;i++) if(!vis[i]) vis[i]=1;else vis[i]=0;
	for(int i=1;i<=n;i++) vis[i]=vis[i-1]+vis[i]; 
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans+=T.query(p[i].b);
		T.update(p[i].b,1);
	}
	T.clear();
	int iv1=ksm(vis[n],mod-2),iv2=ksm(vis[n]-1,mod-2),sum=0;
	for(int i=1;i<=n;i++) if(vis[i]-vis[i-1])
	(sum+=iv1*iv2%mod*vis[i-1]%mod)%=mod;
	for(int i=1;i<=n;i++)
	if(p[i].c!=-1)
	{
		ans+=T.query(p[i].c); T.update(p[i].c,1);
		int tmp=T2.query(n),tmp2=vis[p[i].c]; (ans+=tmp*tmp2%mod*iv1)%=mod;
		tmp=all-tmp; tmp2=vis[n]-vis[p[i].c]; (ans+=tmp*tmp2%mod*iv1)%=mod;
	}
	else {int tmp=T2.query(n); ans=(ans+tmp*sum%mod)%mod; T2.update(1,1);}
	T.clear();T2.clear(); sort(p+1,p+1+n,cmp2);
	for(int i=1;i<=n;i++)
	if(p[i].c!=-1)
	{
		ans+=T.query(p[i].c); T.update(p[i].c,1);
		int tmp=T2.query(n),tmp2=vis[p[i].c]; (ans+=tmp*tmp2%mod*iv1)%=mod;
		tmp=all-tmp; tmp2=vis[n]-vis[p[i].c]; (ans+=tmp*tmp2%mod*iv1)%=mod;
	}
	else {int tmp=T2.query(n);ans=(ans+tmp*sum%mod)%mod;T2.update(1,1);}
	ans=(ans-((n*(n-1)/2)%mod)+mod)*ksm(2,mod-2)%mod;
	printf("%lld\n",ans%mod);
}

T4 追逐

先咕了。。。

posted on 2021-11-13 07:13  JYFHYX  阅读(38)  评论(0编辑  收藏  举报