2.8模拟总结

前言

80pts
30+30+20
rnk10
三个暴力分…
T2拿虚树玩了半天结果假了qwq
乍一看似乎都挺可做的。
但是一道都做不出来
(觉得写考场过程有点流水账,不写了,一些想说的写在对应题目里吧)

题目解析

T1 三角查找(triangle)

乍一看巨可做的题,但想了很久也没做出来…
枚举线段,在距离上二分找点的做法也想到过,但是当时就卡在如何维护点关于不同线段的距离始终有序上。
题解的做法挺巧妙的,两个点关于某条线段的距离的偏序关系是由它们连线和当前线段斜率相对大小关系决定的,所以把线段极角排序,一开始把点按照第一个线段的距离sort一遍,之后枚举到当前线段就把线段两端点swap一下即可。
说实话,这个玄学做法考场即使我观察到斜率的性质可能也不太敢写,太诡异了。
但确实是对的。

T2 连通的图(connected)

这次考试就砸这题上了。
建个生成树再找基环显而易见,然后我猜了个结论,在n=2的时候都是对的(所以我就得了30分),我就以为可以推广了。
为什么不试试n=3啊!!
然后为这个结论服务我就开始兴致勃勃的建虚树,然后写一些类似 k k k^k kk 的暴搜,似乎能过不少分的。
但是最后事实是k=8都会T,因为我那个虚树的结点数是 O ( k ) O(k) O(k),挂个四倍常数左右

所以我只挂了20分!
正解的关键是一个结论:

令第 i i i 条非树边的权值为 2 i 2^i 2i,树边权值为覆盖其的非树边的异或和,则图不连通的充要条件是断边集合的一个子集权值异或和为0。

这个结论似乎见到过,但是考试的时候没有想到…
有了这个结论,写个暴搜用线性基判一下合法就行了。
必须在搜索过程中判到非法直接返回,不然会T(别问我为什么知道)
复杂度 O ( 玄 学 ) O(玄学) O()

T3 奇妙的树(graph)

这个题的感觉挺难的,主要感觉就是方向太多了,难以找到有用的那一个。
题目的性质其实就是按照bfs序编号
g i = max ⁡ j , f a j < i g_i=\max j,fa_j<i gi=maxj,faj<i,那么对于一次询问 ( l , r ) (l,r) (l,r),那么所有的贡献答案的点对有且仅有 [ l , min ⁡ ( r , g l ) ] [l,\min(r,g_l)] [l,min(r,gl)] 的每个点各自的子树内的所有点对,那么也就是编号属于 [ l , r ] [l,r] [l,r] 的结点在子树内权值和的平方。
如何快速统计这个东西?
考虑分块,预处理时每经过 n \sqrt n n 个结点就统计一遍子树权值平方和,然后每次询问的时候找到对应所在块,利用预处理的前缀和快速算出答案,再把 O ( n ) O(\sqrt n) O(n ) 的散点暴力维护进去。
暴力维护需要一个 k 级祖先,讲解说树剖常数小都能过,我长剖 O ( 1 ) O(1) O(1) 都过不去,服了。

代码

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=2e3+100;
const int M=2e5+100;
const double inf=1e18;
const int mod=998244353;

int n;
ll m;
struct pt{
	ll x,y;
}p[N];
inline pt operator - (const pt &a,const pt &b){
	return (pt){a.x-b.x,a.y-b.y};
}
inline ll operator ^ (const pt &a,const pt &b){
	return a.x*b.y-b.x*a.y;
}
struct line{
	int a,b;
	double k;
	bool operator < (const line oth){
		return k<oth.k;
	}
}l[N*N];

int tot;
int x[N],A,B;
inline ll calc(int x){
	return (p[B]-p[A])^(p[x]-p[A]);
}
bool cmp(int x,int y){
	return calc(x)<calc(y);
}
int find(ll val){
	int st=1,ed=n;
	while(st<ed){
		int mid=(st+ed)>>1;
		ll res=calc(x[mid]);
		if(res>=val) ed=mid;
		else st=mid+1;
	}
	return x[st];
}
int pl[N];

signed main(){
	freopen("triangle.in","r",stdin);
	freopen("triangle.out","w",stdout);
	n=read();m=read();
	m<<=1;
	for(int i=1;i<=n;i++){
		p[i].x=read();p[i].y=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			l[++tot]=(line){i,j,p[i].x==p[j].x?inf:1.0*(p[j].y-p[i].y)/(p[j].x-p[i].x)};
		}
	}
	sort(l+1,l+1+tot);
	A=l[1].a;B=l[1].b;
	for(int i=1;i<=n;i++) x[i]=i;
	sort(x+1,x+1+n,cmp);
	for(int i=1;i<=n;i++) pl[x[i]]=i;
	for(int i=1;i<=tot;i++){
		A=l[i].a;B=l[i].b;
		//printf("\n(%d %d) mid=%d\n",A,B,pl[A]);
		//for(int j=1;j<=n;j++) printf("%d ",x[j]);
		//puts("");
		int st=1,ed=pl[A],o(0);
		while(st<ed){
			int mid=(st+ed+1)>>1;
		//	printf("  (%d %d) mid=%d calc=%lld\n",st,ed,mid,abs(calc(x[mid])));
			if(abs(calc(x[mid]))>=m) st=mid;
			else ed=mid-1;
		}
		o=x[st];
		//printf("o=%d\n",o);
		if(abs(calc(o))==m){
			puts("Yes");
			printf("%lld %lld\n",p[o].x,p[o].y);
			printf("%lld %lld\n",p[A].x,p[A].y);
			printf("%lld %lld\n",p[B].x,p[B].y);
			return 0;
		}
		st=pl[A],ed=n;
		while(st<ed){
			int mid=(st+ed)>>1;
			if(abs(calc(x[mid]))>=mid) ed=mid;
			else st=mid+1;
		}
		o=x[st];
		//printf("  o=%d\n",o);
		if(abs(calc(o))==m){
			puts("Yes");
			printf("%lld %lld\n",p[o].x,p[o].y);
			printf("%lld %lld\n",p[A].x,p[A].y);
			printf("%lld %lld\n",p[B].x,p[B].y);
			return 0;
		}
		swap(x[pl[A]],x[pl[B]]);
		swap(pl[A],pl[B]);
	}
	puts("No");
	return 0;
}
/*
5 2
2 4
1 5
1 2
2 3
3 4
3 5
*/
 

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=2e5+100;
const int inf=1e9;
const int mod=998244353;

int n,m;
struct node{
	int to,nxt;
}p[N<<1];
int fi[N],cnt;
bool tag[N<<1];
inline void addline(int x,int y){
	p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
}
int u[25],v[25],num;
int pl[N][20],dep[N],dfn[N],tim;
void dfs1(int x,int f){
	dep[x]=dep[f]+1;
	pl[x][0]=f;
	for(int k=1;pl[x][k-1];++k) pl[x][k]=pl[pl[x][k-1]][k-1];
	dfn[x]=++tim;
	for(int i=fi[x];~i;i=p[i].nxt){
		int to=p[i].to;
		if(to==f) continue;
		if(dep[to]){
			tag[i]=tag[i^1]=1;
			if(dep[to]<dep[x]){
				++num;u[num]=x;v[num]=to;
			}
			continue;
		}
		dfs1(to,x);
	}
	return;
}
int val[N];
void dfs2(int x,int f){
	for(int i=fi[x];~i;i=p[i].nxt){
		int to=p[i].to;
		if(tag[i]||to==f) continue;
		dfs2(to,x);
		val[x]^=val[to];
	}
	return;
}
int bac[N],w[N],tot;

ll ans(0);

int b[20],x[100];
int pos,ori;
bool ins(int now){
	for(int k=m-1;k>=0;k--){
		if(!(now&(1<<k))) continue;
		if(!b[k]){
			pos=k;ori=b[k];
			b[k]=now;
			return true;
		}
		now^=b[k];
	}
	return false;
}

void solve(int k,int num,ll cur){
	if(k>tot){
		ans=(ans+cur)%mod;
		return;
	}
	solve(k+1,num,cur);
	if(ins(w[k])){
		int p=pos,o=ori;
		solve(k+1,num+1,cur*bac[w[k]]%mod);
		b[p]=o;
	}	
}

signed main(){
	freopen("connected.in","r",stdin);
	freopen("connected.out","w",stdout);
	memset(fi,-1,sizeof(fi));cnt=-1;
	n=read();m=read();
	for(int i=1;i<=n+m-1;i++){
		int x=read(),y=read();
		addline(x,y);addline(y,x);
	}
	dfs1(1,0);
	for(int i=1;i<=m;i++){
		//printf("(%d %d)\n",u[i],v[i]);
		val[u[i]]^=(1<<(i-1));
		val[v[i]]^=(1<<(i-1));
	}
	dfs2(1,0);
	for(int i=2;i<=n;i++){
		//printf("i=%d val=%d\n",i,val[i]);
		if(bac[val[i]]==0) w[++tot]=val[i];
		bac[val[i]]++;
	}
	for(int i=1;i<=m;i++){
		if(bac[1<<(i-1)]==0) w[++tot]=1<<(i-1);
		bac[1<<(i-1)]++;
	}
	//for(int i=1;i<=tot;i++) printf("w=%d bac=%d\n",w[i],bac[w[i]]);
	solve(1,0,1);
	printf("%lld\n",ans);
	return 0;
}
/*
5 2
2 4
1 5
1 2
2 3
3 4
3 5
*/
 

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=5e3+100;
const int M=2e5+100;
const int inf=1e9;
const int mod=998244353;

int n,m;
struct node{
	int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){
	p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
}
ll s[N][N],val[N];
void dfs(int x){
	s[x][x]=val[x];
	for(int i=fi[x];~i;i=p[i].nxt){
		int to=p[i].to;
		dfs(to);
		for(int j=1;j<=n;j++) s[x][j]=(s[x][j]+s[to][j])%mod;
	}
}
int l,r;
ll solve(int x){
	ll ans(0);
	for(int i=fi[x];~i;i=p[i].nxt){
		int to=p[i].to;
		ans=(ans+solve(to))%mod;
	}
	if(l<=x&&x<=r){
		ll now=val[x];
		ans=(ans+now*now)%mod;
		for(int i=fi[x];~i;i=p[i].nxt){
			int to=p[i].to;
			ll add=(s[to][r]-s[to][l-1]+mod)%mod;
			ans=(ans+2*now*add)%mod;
			now=(now+add)%mod;
		}
	}
	return ans;
}

signed main(){
	freopen("slight.in","r",stdin);
	freopen("slight.out","w",stdout);
	memset(fi,-1,sizeof(fi));cnt=-1;
	n=read();m=read();
	for(int i=1;i<=n;i++) val[i]=read();
	for(int i=2;i<=n;i++) addline(read(),i);
	dfs(1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) s[i][j]=(s[i][j]+s[i][j-1])%mod;
	}
	int lst(0);
	for(int i=1;i<=m;i++){
		l=read()^lst,r=read()^lst;
		printf("%d\n",lst=solve(1));
	}
	return 0;
}
/*
5 2
2 4
1 5
1 2
2 3
3 4
3 5
*/
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值