北京Day 19

今天血亏。

T1

题目大意:对于给出的一个不保证合法的括号序列,交换括号的位置使得括号序列合法,问最少交换多少个?

题解:送分题。统计未能匹配的括号个数,(x+1)/2即为答案。(然而写的暴力)

T1AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
inline int re_ad()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline bool read(){char ch=getchar();while(ch!='('&&ch!=')')ch=getchar();return ch=='(';}
int n,lnum=0,rnum=0,l,r,ans=0;
bool fla[100010];
inline void getz()
{
	while(l<r)
	{
	if(fla[l])++lnum;
	else{if(!lnum)return;--lnum;}
	++l;
	}
}
inline void gety()
{
	while(l<r)
	{
	if(!fla[r])++rnum;
	else {if(!rnum)return;--rnum;}
	--r;
	}
}
int main()
{
	register int i;
	n=re_ad();
	for(i=1;i<=n;++i)fla[i]=read(),lnum+=fla[i];
	if(lnum*2!=n){cout<<-1<<endl;return 0;}
	l=1;r=n;lnum=0;
	while(l<r)
	{
	getz();gety();
	if(l>=r)break;
	++ans;swap(fla[l],fla[r]);
	}
	cout<<ans<<endl;
}

T2

题目大意:维护一棵带点权二叉树,支持子树翻转和点权修改,动态询问每个点是否能被平衡树规则访问到。

题解:(数据极水,暴力可过)

一个点能被访问到的充要条件是到根的路径上,所有右父亲都比左儿子大,所有左父亲都比右儿子小

每个点记与父亲节点关系是否合法,每个修改操作影响到的节点都是常数个,树链剖分后维护线段树即可

查询即查询一个点到根路径上是否有非法节点,记得维护是否有相同节点。

T2AC代码(暴力)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
inline int re_ad()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline int mi(int x,int y){return x<y?x:y;}
inline int ma(int x,int y){return x>y?x:y;}
int n,m,val[100010],ls[100010],rs[100010],fa[100010],nu;
bool ask(int x,int num)
{
	if(num==val[x])++nu;if(x==1)return true;
	if(x==ls[fa[x]]){if(num>=val[fa[x]])return false;}
	else if(num<=val[fa[x]])return false;
	return ask(fa[x],num);
}
int main()
{
	register int i,op,x,num;
	n=re_ad();m=re_ad();
	for(i=1;i<=n;++i)
	{
	val[i]=re_ad();ls[i]=re_ad();rs[i]=re_ad();
	if(ls[i])fa[ls[i]]=i;if(rs[i])fa[rs[i]]=i;
	}
	while(m--)
	{
	op=re_ad();x=re_ad();
	if(op==1){val[x]=re_ad();}
	if(op==2){swap(ls[x],rs[x]);}
	if(op==3){nu=0;if(ask(x,val[x])&&nu==1)puts("YES");else puts("NO");}
	}
}

T3

题目大意:给定一棵n个节点的树,每次询问以x为根的子树中与x的距离不小于k的节点个数。

题解:长链剖分即可。

T3AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
inline int re_ad()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
	return x*f;
}
void pu_t(long long x){if(x>9)pu_t(x/10);putchar(x%10+48);}
inline int mi(int x,int y){return x<y?x:y;}
int n,A[2600000],d[2600000],son[2600000],dfn[2600000],tot,Q;
long long f[2600000],ans[2600000];
vector<int> g[2600000];
struct node{int k,id;};
vector<node>ask[2600000];
void dfs(int x)
{
	register int i,sz=g[x].size(),v,mx=-1;;
	for(i=0;i<sz;++i)
	{
	v=g[x][i];
	dfs(v);
	if(d[v]>mx){son[x]=v;mx=d[v];}
	}
	d[x]=mx+1;
}
void dfs2(int x)
{
	register int i,j,sz=g[x].size(),v;
	dfn[x]=++tot;
	if(son[x])dfs2(son[x]);
	for(i=0;i<sz;++i)
	{
	v=g[x][i];
	if(v==son[x])continue;
	dfs2(v);
	for(j=0;j<=d[v];++j){f[dfn[son[x]]+j]+=f[dfn[v]+j];}
	}
	f[dfn[x]]=f[dfn[son[x]]]+A[x];
	sz=ask[x].size();
	long long *fx=f+dfn[x];
	for(i=0;i<sz;++i){if(ask[x][i].k<=d[x])ans[ask[x][i].id]=*(fx+ask[x][i].k);}
}
inline void print()
{
	register int lim=re_ad();
	for (register int i = 1; i <= Q;)
	{
	register long long res=0;
	for (register int j = i; j <= mi(Q, i + lim - 1); j++) res^= ans[j];
	i+=lim;
	pu_t(res);putchar('\n');
	}
}
int main()
{
	register int i,an;
	n=re_ad();
	for(i=1;i<=n;++i)A[i]=re_ad();
	for(i=2;i<=n;++i)g[re_ad()].push_back(i);
	Q=re_ad();
	for(i=1;i<=Q;++i)an=re_ad(),ask[an].push_back((node){re_ad(),i});
	dfs(1);dfs2(1);
	print();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值