Problem A: Fairy

Time Limit: 1000 ms Memory Limit: 256 MB

Description

给定n个点,m条边的无向图(无自环),可以从图中删除一条边,问删除哪些边可以使图变成一个二分图。

Input

第1行包含两个整数n,m,分别表示点数和边数。

第2~m+1行每行两个数x,y,表示有一条边连接点x,y。

Output

第一行两个整数,表示能删除的边的个数。

接下来一行按照从小到大的顺序输出能删除的边的编号。

Sample Input
4 4
1 2
1 3
2 4
3 4
Sample Output
4
1 2 3 4

HINT

10%的数据,n,m<=10

40%的数据,n,m<=1000

70%的数据,n,m<=100000

100%的数据,n,m<=2000000

Solution

我们用两个数组odd和eve,odd[u]表示经过(u,fa)这条边的奇环有几个,eve则是欧环

对于整个图,如果一个奇环都没有,那么随便选择哪条边都是答案。

如果只有一个奇环,那么奇环上的所有不在欧环上的边都是答案。

若有多个奇环,则只有经过(u,fa)这条边的奇环个数和总奇环个数一样且没有欧环经过它才能满足条件。

如何统计奇环和欧环呢?考虑差分统计:

首先跑出整个图的dfs树,对于那些不在dfs树上的边,我们差分统计,如图:

然后统计就搞定了。代码实现如下:

#include<bits/stdc++.h>
using namespace std;
struct qwq{int v;int nxt;int id;
}edge[4000001];
int head[4000001];
int cnt=-1;
void add(int u,int v,int id){edge[++cnt].nxt=head[u];edge[cnt].v=v;edge[cnt].id=id;head[u]=cnt;
}
int tmp1[4000001],tmp2[4000001];
int odd[4000001],eve[4000001];
int fa[4000001],dep[4000001];
bool mk[4000001];
int ans;
int tmp;
int n,m;
void dfs(int u){for(int i=head[u];~i;i=edge[i].nxt){int v=edge[i].v;if(!dep[v]){fa[v]=u,dep[v]=dep[u]+1;mk[edge[i].id>m?edge[i].id-m:edge[i].id]=true;dfs(v);odd[u]+=odd[v],eve[u]+=eve[v];}else if(v!=fa[u]&&dep[v]<dep[u]){if((dep[u]-dep[v])%2==1){tmp2[u]++,tmp2[v]--;}else {ans++;tmp1[u]++,tmp1[v]--;tmp=edge[i].id>m?edge[i].id-m:edge[i].id;}}}odd[u]+=tmp1[u],eve[u]+=tmp2[u];
}
int tot;
int anss[4000001];
struct ed{int u,v;
}e[4000001];
int main(){memset(head,-1,sizeof(head));scanf("%d%d",&n,&m);for(int i=1;i<=m;++i){int u,v;scanf("%d%d",&u,&v);add(u,v,i),add(v,u,i+m);e[i].u=u,e[i].v=v;}for(int i=1;i<=n;++i){if(!dep[i]){dep[i]=1;dfs(i);}}if(ans==0){printf("%d\n",m);for(int i=1;i<=m;++i)printf("%d ",i);return 0;}if(ans==1){anss[++tot]=tmp;}//for(int i=1;i<=n;++i){//  cout<<odd[i]<<" "<<eve[i]<<endl;//}for(int i=1;i<=m;++i){if(mk[i]){int u;if(fa[e[i].v]==e[i].u)u=e[i].v;if(fa[e[i].u]==e[i].v)u=e[i].u;if(odd[u]==ans&&eve[u]==0){anss[++tot]=i;}}}printf("%d\n",tot);sort(anss+1,anss+tot+1);for(int i=1;i<=tot;++i)printf("%d ",anss[i]);
}

Problem B: Phorni

Time Limit: 3000 ms Memory Limit: 512 MB

Description

给你一个字符串S,初始长度为len,还有一个n个元素的序列P。

接下来m个操作,有三种类型,分别是:

  1. 在字符串前面加入一个字符

  2. 修改P中一个元素的值

  3. 询问对于所有i∈[l,r],使得S[L-P[i]+1..L]字典序最小的i(有多个则输出最小的i,L是当前字符串长度)

(强制在线)

Input

输入共 m + 3 行。

第一行为三个整数n, m, len。

第二行为初始字符串S。

第三行,n个数,表示P[1]…p[n]。

接下来 m 行,每行表示一个操作。

  1. I c 在字符串最前的位置加入第 (c xor lastans)+1 个小写字母,其中lastans 为上一次Q询问的答案,初始为0。

  2. C x pos 将P[x]修改为pos。

  3. Q l r 表示询问[l..r]区间。

Output

对于每个Q询问输出一行,表示答案。

Sample Input
3 3 5
horni
3 2 5
I 15
C 1 6
Q 1 3
Sample Output
3

HINT

对于10%的数据,1<=n<=100,1<=m<=100,1<=len<=100,1<=P[i]<=len。

对于100%的数据, 1<=n<=500000,1<=m<=800000,1<=len<=100000,1<=P[i]<=len。

I操作中0<=c xor lastans<=25。

C操作中1<=x<=n,1<=pos<=当前字符串长度。

Q操作中1<=l,r<=n。

I操作数量约占总操作数量的1/5,C,Q操作数量约各占总操作数量的2/5。

Solution

嗯,后缀平衡树板子题

我们以从短到长的顺序插入后缀

考虑如何快速判断两个后缀的字典序大小:

如果首字母不同则直接判断;

否则判断两个后缀的上一个后缀的大小。

因为是从短到长插入的,所以上一个后缀肯定已经处理好了

然后如果新加入一个后缀,我们不用修改前面的后缀顺序(显然),直接插入即可

对于这棵平衡树,我们对于每个节点设置l、r,节点的权值为val=(l+r)/2

左儿子的l、r即为l、val-1,这样就可以保证中序遍历后这个序列是单调递增的

为了满足这个特性,我们一定要使用一种平衡树——重量平衡树才能实现

所以我们选用替罪羊树。然后对于区间的查询,套个线段树就可以了

#include<bits/stdc++.h>
using namespace std;
int read(){int num=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){num=num*10+ch-'0';ch=getchar();}return num*f;
}
struct node{double l,r,val;int ch[2];int siz;
}t[1000001];
int tot;
int rt;
char str[1000001];
const double alp=0.75;
void newnode(int x,double l,double r){t[x].l=l,t[x].r=r;t[x].val=(l+r)/2;t[x].siz=1,t[x].ch[0]=t[x].ch[1]=0;
}
void pushup(int x){t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;
}
bool isbad(int x){return t[t[x].ch[0]].siz>t[x].siz*alp||t[t[x].ch[1]].siz>t[x].siz*alp;
}
int que[1000001],L;
void dfs(int x){if(t[x].ch[0])dfs(t[x].ch[0]);que[++L]=x;if(t[x].ch[1])dfs(t[x].ch[1]);
}
int build(int l,int r,double x,double y){if(l>r)return 0;int mid=(l+r)/2;int k=que[mid];newnode(k,x,y);t[k].ch[0]=build(l,mid-1,x,t[k].val);t[k].ch[1]=build(mid+1,r,t[k].val,y);pushup(k);return k;
}
void rebuild(int &k){L=0;dfs(k);k=build(1,L,t[k].l,t[k].r);
}
int sta[1000001],top;
void Re(){for(int i=1;i<=top;++i){if(isbad(sta[i])){if(i==1)rebuild(rt);else {rebuild(t[sta[i-1]].ch[t[sta[i-1]].ch[1]==sta[i]]);pushup(sta[i-1]); }return;}}
}
bool cmp(int x,int y){return str[x]==str[y]?t[x-1].val<t[y-1].val:str[x]<str[y];
}
void ins(int p){tot++;if(!rt){rt=tot;newnode(tot,1,1e18);return;}top=0;int k=rt;while(233){bool d=cmp(k,p);sta[++top]=k;t[k].siz++;if(!t[k].ch[d]){t[k].ch[d]=tot;if(d)newnode(tot,t[k].val,t[k].r);else newnode(tot,t[k].l,t[k].val);break;}k=t[k].ch[d];}Re();
}
int len[1000001];
int minn[4000001];
int pushup(int x,int y){return t[len[x]].val<=t[len[y]].val?x:y;
}
void Build(int o,int l,int r){if(l==r){minn[o]=l;return;}int mid=(l+r)/2;Build(o*2,l,mid);Build(o*2+1,mid+1,r);minn[o]=pushup(minn[o*2],minn[o*2+1]);
}
void update(int o,int l,int r,int pos){if(l==r){minn[o]=l;return;}int mid=(l+r)/2;if(pos<=mid)update(o*2,l,mid,pos);else update(o*2+1,mid+1,r,pos);minn[o]=pushup(minn[o*2],minn[o*2+1]);
}
int query(int o,int l,int r,int L,int R){if(L<=l&&r<=R)return minn[o];int mid=(l+r)/2;if(R<=mid)return query(o*2,l,mid,L,R);if(mid<L)return query(o*2+1,mid+1,r,L,R);return pushup(query(o*2,l,mid,L,R),query(o*2+1,mid+1,r,L,R));
}
int main(){int n=read(),q=read(),m=read();scanf("%s",str+1);reverse(str+1,str+1+m);for(int i=1;i<=n;++i){len[i]=read();}for(int i=1;i<=m;++i)ins(i);Build(1,1,n);int lst=0;char opt[12];for(int i=1;i<=q;++i){scanf("%s",opt);if(opt[0]=='I'){int x=read();str[++m]='a'+(x^lst);ins(m);}if(opt[0]=='C'){int x=read(),pos=read();len[x]=pos;update(1,1,n,x);}if(opt[0]=='Q'){int l=read(),r=read();printf("%d\n",lst=query(1,1,n,l,r));}}
}

Problem C: The Winds of Winter

Time Limit: 1000 ms Memory Limit: 512 MB

Description

给定一棵n个点的树,对于树上每个结点,将它删去,然后可以将得到的森林中任意一个点与其父亲断开并连接到另一颗树上,对每一个点求出森林中所有树size最大值的最小值。

Input

第一行,一个数n。

第2~n+1行,每行两个整数x,y,(1<=x<=y<=n),表示x是y的父亲(若x=0则y为根)。

Output

共n行,每行一个数,第i行表示删去点i后的答案。

Sample Input
10
0 1
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
5 10
Sample Output
3
4
5
5
5
9
9
9
9
9

HINT

10%的数据,n<=10

30%的数据,n<=10^3

100%的数据,n<=10^5

Solution

首先考虑怎样能让最大值最小

设一个点最大的子树(头上的也算)为maxn[u],最小为minn[u],次大为sec[u],改变的值为val

由于只能操作一次,所以我们最后的答案肯定是从maxn[u]上取下一棵子树塞到minn[u]上

于是我们的答案肯定为\(max(maxn[u]-v,sec[u],minn[u]+v)\)。然后我们要找的v应当尽量靠近\((maxn[u]-minn[u]) \over 2\)

所以开三棵权值线段树,一棵存总体(除了自己到根的路径上的点)的siz,一棵存当前子树的siz,一棵存从当前节点到根路径上所有点的siz

如果最大子树是自己的子树,那么直接就在存当前子树的权值线段树里找到最贴近答案的即可

否则在自己到根路径上以及路径外查找最佳答案即可。

细节实现超级麻烦。

#include<bits/stdc++.h>
using namespace std;
#define INF 2147483647
struct seg{bool tag[500001];int sum[500001];void pushdown(int o){if(!tag[o])return;tag[o*2]=tag[o*2+1]=1;sum[o*2]=sum[o*2+1]=0;tag[o]=0;}void clear(){tag[1]=1,sum[1]=0;}void update(int o,int l,int r,int pos,int val){if(l==r){sum[o]+=val;return;}pushdown(o);int mid=(l+r)/2;if(pos<=mid)update(o*2,l,mid,pos,val);else update(o*2+1,mid+1,r,pos,val);sum[o]=sum[o*2]+sum[o*2+1];}int querymin(int o,int l,int r,int L,int R){if(!sum[o]||L>R)return INF;if(l==r)return l;pushdown(o);int mid=(l+r)/2;int ret=INF;if(L<=mid)ret=min(ret,querymin(o*2,l,mid,L,R));if(ret!=INF)return ret;if(mid<R)ret=min(ret,querymin(o*2+1,mid+1,r,L,R));return ret; }int querymax(int o,int l,int r,int L,int R){if(!sum[o]||L>R)return 0;if(l==r)return l;pushdown(o);int mid=(l+r)/2;int ret=0;if(mid<R)ret=max(ret,querymax(o*2+1,mid+1,r,L,R));if(ret)return ret;if(L<=mid)ret=max(ret,querymax(o*2,l,mid,L,R));return ret; }
}t1,t2,t3;
int query1(int o,int l,int r,int L,int R){if(t1.sum[o]-t3.sum[o]<=0||L>R)return INF;if(l==r)return l;t3.pushdown(o);int mid=(l+r)/2;int ret=INF;if(L<=mid)ret=min(ret,query1(o*2,l,mid,L,R));if(ret!=INF)return ret;if(mid<R)ret=min(ret,query1(o*2+1,mid+1,r,L,R));return ret;
}
int query2(int o,int l,int r,int L,int R){if(t1.sum[o]-t3.sum[o]<=0||L>R)return 0;if(l==r)return l;t3.pushdown(o);int mid=(l+r)/2;int ret=0;if(mid<R)ret=max(ret,query2(o*2+1,mid+1,r,L,R));if(ret)return ret;if(L<=mid)ret=max(ret,query2(o*2,l,mid,L,R));return ret;
}
int n;
struct qwq{int v;int nxt;
}edge[500001];
int head[500001];
int cnt=-1;
void add(int u,int v){edge[++cnt].nxt=head[u];edge[cnt].v=v;head[u]=cnt;
}
void upd(int &mx,int &sc,int &mi,int val,int &id,int i){if(val>=mx){sc=mx;mx=val;id=i;}else if(val>sc)sc=val;if(val)mi=min(mi,val);
}
int siz[500001];
int maxn[500001],sec[500001],minn[500001];
int mx[500001],bigs[500001];
void pre(int u,int fa){siz[u]=1,mx[u]=-1;for(int i=head[u];~i;i=edge[i].nxt){int v=edge[i].v;if(v==fa)continue;pre(v,u);siz[u]+=siz[v];upd(maxn[u],sec[u],minn[u],siz[v],mx[u],v);}bigs[u]=mx[u];upd(maxn[u],sec[u],minn[u],n-siz[u],mx[u],0);t1.update(1,1,n,siz[u],1);
}
bool vis[500001];
void updson(int u,int fa){t3.update(1,1,n,siz[u],1);for(int i=head[u];~i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||vis[v])continue;updson(v,u);}
}
int ans[500001];
void solve(int u,int fa){t1.update(1,1,n,siz[u],-1);t2.update(1,1,n,siz[u],1);for(int i=head[u];~i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||v==bigs[u])continue;solve(v,u);t3.clear();}if(bigs[u]!=-1)solve(bigs[u],u),vis[bigs[u]]=true;int tmp=0;if(mx[u]==bigs[u]){tmp=t3.querymax(1,1,n,1,(maxn[u]-minn[u])/2);ans[u]=max(sec[u],max(maxn[u]-tmp,minn[u]+tmp));tmp=t3.querymin(1,1,n,(maxn[u]-minn[u])/2,n);ans[u]=min(ans[u],max(sec[u],max(maxn[u]-tmp,minn[u]+tmp)));}//cout<<u<<" "<<ans[u]<<endl;updson(u,fa);t1.update(1,1,n,siz[u],1);t2.update(1,1,n,siz[u],-1);if(mx[u]!=bigs[u]){tmp=max(query2(1,1,n,1,(maxn[u]-minn[u])/2),t2.querymax(1,1,n,1+siz[u],min((maxn[u]-minn[u])/2+siz[u],n))-siz[u]);ans[u]=max(sec[u],max(maxn[u]-tmp,minn[u]+tmp));tmp=min(query1(1,1,n,(maxn[u]-minn[u])/2,n),t2.querymin(1,1,n,(maxn[u]-minn[u])/2+siz[u],n)-siz[u]);ans[u]=min(ans[u],max(sec[u],max(maxn[u]-tmp,minn[u]+tmp)));} if(bigs[u]!=-1)vis[bigs[u]]=false;
}
int rt;
int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);memset(head,-1,sizeof(head));memset(minn,127,sizeof(minn));scanf("%d",&n);for(int i=1;i<=n;++i){int u,v;scanf("%d%d",&u,&v);if(u==0){rt=v;continue;}add(u,v),add(v,u);}pre(rt,-1);solve(rt,-1);for(int i=1;i<=n;++i)printf("%d\n",ans[i]);
}

转载于:https://www.cnblogs.com/youddjxd/p/11425774.html

[补档]noip2019集训测试赛(十三)相关推荐

  1. [补档]noip2019集训测试赛(九)

    因为这次考试我一道题都不会,所以先不写了 转载于:https://www.cnblogs.com/youddjxd/p/11442143.html

  2. [补档]noip2019集训测试赛(八)

    Problem B: 2048 Special Judge Time Limit: 1000 ms Memory Limit: 256 MB Description 2048曾经是一款风靡全球的小游戏 ...

  3. [补档]noip2019集训测试赛(十)

    Problem A: fibonacci Time Limit: 2000 ms Memory Limit: 256 MB Description 小y最近迷上了fibonacci数列,他定义了一种数 ...

  4. [补档]noip2019集训测试赛(十二)

    Problem A: 记忆(memory) Time Limit: 1000 ms Memory Limit: 512 MB Description 你在跟朋友玩一个记忆游戏. 朋友首先给你看了n个长 ...

  5. [补档]noip2019集训测试赛(十四)

    Problem A: Fibonacci(fib.pas/cpp) Time Limit: 1000 ms Memory Limit: 128 MB Description 豆豆最近迷上了Fibona ...

  6. [补档]noip2019集训测试赛(十五)

    Problem A: 传送带 Time Limit: 1000 ms Memory Limit: 256 MB Description 在一个二维平面上有两条传送带,每一条传送带可以看成是一条线段.两 ...

  7. noip2019集训测试赛(五)

    Problem A: lcm Time Limit: 1000 ms Memory Limit: 256 MB Sample Input 3 1 2 5 Sample Output 1 4 55 HI ...

  8. noip2019集训测试赛(七)

    Problem A: Maze Time Limit: 1000 ms Memory Limit: 256 MB Description 考虑一个N×M的网格,每个网格要么是空的,要么是障碍物.整个网 ...

  9. 2016北京集训测试赛(十三) Problem B: 网络战争

    Solution KD tree + 最小割树 转载于:https://www.cnblogs.com/ZeonfaiHo/p/7420354.html

最新文章

  1. mpi和openmp混合编程的优点_西门子PLC可编程控制器CPU1215C一级总代理
  2. 我在攻读计算机视觉和机器学习硕士学位时学到了什么
  3. 数据库基础知识——初始MySQL
  4. html遮罩提示框代码,基于jQuery实现弹出可关闭遮罩提示框实例代码
  5. C++中两个类中互相包含对方对象的指针问题
  6. 何必!放着985双一流专业不读,非要当程序员去内卷!
  7. Linux 工程师的 6 类好习惯和 23 个教训
  8. 数据库系统概论——事务
  9. 谷歌浏览器32位安装包_Chromium内核的edge浏览器终于来了,试用了半天,发现真香!...
  10. Android MTP 模式 驱动无法安装解决方案
  11. 走进音视频的世界——新一代开源编解码器AV1
  12. mysql实验报告4_实验四∶数据库安全性实验报告.doc
  13. 1人民币试用世纪互联azure虚拟机,跑CNN训练
  14. Windows平台调试工具:DebugView
  15. 天威TM1668芯片官方资料,讲解,代码,自己写的例程
  16. 代理ARP(Proxy Arp)
  17. 微前端 Micro-Frontends - 概念
  18. 证券中 A、B、C、D字头账号分别代表什么?
  19. 对抗式学习pythonC day1 菜鸟档案
  20. Wonderware-InTouch与PLC的冗余配置

热门文章

  1. MySQL学习8 - 数据的增删改
  2. 07_Python的控制判断循环语句1(if判断for循环)_Python编程之路
  3. 简单选项卡切换(一)
  4. jstl-按照html的形式输出至页面
  5. 【Acm】算法之美—Fire Net
  6. 上海雄联机械配件有限公司
  7. 谈谈var变量提升以及var,let,const的区别
  8. 【PHP学习】—创建PHP文件(一)
  9. String ,StringBuilder,StringBuffer的区分
  10. 为什么要从vmware切换到kvm?