[关闭]
@01010101 2018-10-17T13:42:23.000000Z 字数 5246 阅读 760

1016


T1
这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x,y)):
1、我可以走到(x+1,y)
2、我可以走到(x,y+1)
3、我可以走到(x+1,y+1)
现在我需要你的帮助,帮我找出我最多能够得到多少个果实。
1<=n<=100000,-10^9<=x,y<=10^9

用带一点点扫描线的思想来想,如果按横坐标排序,那么数量就是纵坐标不断递增的。就是最长上升子序列了。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. int read(){
  7. char ch;int op=1;
  8. while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;
  9. int ret=ch-'0';
  10. while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';
  11. return ret*op;
  12. }
  13. const int N=100000+10;
  14. int n,cnt;
  15. int t[N];
  16. struct node{
  17. int xx,yy;
  18. bool operator < (const node &b) const{
  19. if(xx!=b.xx) return xx<b.xx;
  20. return yy<b.yy;
  21. }
  22. }a[N];
  23. int main(){
  24. freopen("find.in","r",stdin);
  25. freopen("find.out","w",stdout);
  26. n=read();
  27. for(int i=1;i<=n;++i){
  28. a[i].xx=read();a[i].yy=read();
  29. }
  30. sort(a+1,a+n+1);
  31. for(int i=1;i<=n;++i){
  32. if(a[i].xx<0||a[i].yy<0) continue;
  33. int b=a[i].yy;
  34. if(b>=t[cnt]){
  35. t[++cnt]=b;
  36. }
  37. else{
  38. int l=1,r=cnt,mid,ans=-1;
  39. while(l<=r){
  40. int mid=(l+r)>>1;
  41. if(t[mid]>b) {ans=mid;r=mid-1;}
  42. else l=mid+1;
  43. }
  44. if(ans!=-1) t[ans]=b;
  45. }
  46. }
  47. printf("%d\n",cnt);
  48. return 0;
  49. }

T2
这是个奇异的世界,世界上的n-1条路联结起来形成一棵树,每条路有一个对应的权值ci。
现在我会给出q组询问或操作。
每次询问我会从一个x点走到y点,初始在x点我会有一个数字v,然后每走过一条权值为c的边,我的v就会变成,问最后到y时v变成了什么。
每次修改我会修改一条边的权值,保证修改后的权值小于等于原来的权值且不会小于1。
每组询问或操作的格式如下:
询问:1 x y v表示从x走到y,一开始的数字为v。
操作:2 p c表示将第p条边的边权修改为c
n,q<=100000,c_i,v_i <= 10^{18}

显然,走过一条非1边后边权至少减半。所以有两种维护方式:1边,或0边。
对于1边:可以用并查集进行路径压缩。
对于0边:可以用树链剖分维护从当前点到根的路径乘积,用double进行乘,超过1e18就置为0。
此题不需要维护精度:
有两个结论:
1.
向下取整只与数值有关,与数的先后无关。
2.
向下取整可以变连除为除一个。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #define ll long long
  5. using namespace std;
  6. ll read(){
  7. char ch;ll op=1;
  8. while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;
  9. ll ret=ch-'0';
  10. while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';
  11. return ret*op;
  12. }
  13. void write(ll x){
  14. if(x<0) putchar('-'),x=-x;
  15. if(x>=10) write(x/10);
  16. putchar('0'+x%10);
  17. }
  18. const ll N=100000+10;
  19. const ll D=20;
  20. ll n,m,k,q;
  21. ll head[N],cst[N],f[N],d[N],fa[N][D+2];
  22. struct edge{
  23. ll v,w,nxt;
  24. }e[N<<1];
  25. void adde(ll u,ll v,ll w){
  26. e[k].v=v;
  27. e[k].w=w;
  28. e[k].nxt=head[u];
  29. head[u]=k++;
  30. }
  31. ll Find(ll x){
  32. return (f[x]==x)?x:f[x]=Find(f[x]);
  33. }
  34. void dfs(ll u,ll fath){
  35. d[u]=d[fath]+1;fa[u][0]=fath;
  36. for(ll i=head[u];i!=-1;i=e[i].nxt){
  37. ll v=e[i].v;
  38. if(v!=fath){
  39. if(e[i].w==1) f[v]=Find(u);
  40. else f[v]=v;
  41. dfs(v,u);
  42. cst[v]=e[i].w;
  43. }
  44. }
  45. }
  46. ll Lca(ll u,ll v){
  47. if(d[u]<d[v]) swap(u,v);
  48. for(ll i=D;i>=0;--i){
  49. if(d[fa[u][i]]>=d[v]) u=fa[u][i];
  50. }
  51. if(u==v) return u;
  52. for(ll i=D;i>=0;--i){
  53. if(fa[u][i]!=fa[v][i]){
  54. u=fa[u][i];
  55. v=fa[v][i];
  56. }
  57. }
  58. return fa[u][0];
  59. }
  60. ll up_tree(ll u,ll t,ll cc){
  61. while(d[u]>d[t]&&cc!=0){
  62. cc/=cst[u];
  63. if(f[u]!=u) u=f[u];
  64. else u=fa[u][0];
  65. }
  66. return cc;
  67. }
  68. ll a,b,c,op;
  69. int main(){
  70. // freopen("walk.in","r",stdin);
  71. // freopen("walk.out","w",stdout);
  72. memset(head,-1,sizeof(head));
  73. scanf("%lld%lld",&n,&q);
  74. for(ll i=1;i<n;++i){
  75. a=read();b=read();c=read();
  76. adde(a,b,c);adde(b,a,c);
  77. }
  78. f[1]=1;
  79. dfs(1,0);
  80. for(ll i=1;i<=D;++i){
  81. for(ll j=1;j<=n;++j){
  82. fa[j][i]=fa[fa[j][i-1]][i-1];
  83. }
  84. }
  85. while(q--){
  86. op=read();
  87. if(op==1){
  88. a=read();b=read();c=read();
  89. ll l=Lca(a,b);
  90. write(up_tree(b,l,up_tree(a,l,c)));
  91. putchar('\n');
  92. }
  93. else{
  94. a=read();b=read();
  95. if(b==1) {
  96. f[e[2*a-2].v]=Find(e[2*a-1].v);
  97. }
  98. cst[e[2*a-2].v]=b;
  99. }
  100. }
  101. return 0;
  102. }

T3
这是个有n个点的世界,有m条无向边连接着这n个点,但是不保证点之间能够互相到达。
“这个世界的夕阳,只在奇数长的简单路径的尽头。”一个神如是说。
于是我想知道对于一个点对(x,y),x到y之间的所有简单路径中是否存在长度为奇数的路径,只有这样,我才能找到存在有夕阳的路。保证没有自环与重边。
1≤n,q,m≤100000

此题的考察知识较多。

题解:
假设我们现在对原图先得到一棵生成树(其实应该是森林,毕竟不保证联通)
那么我们对于询问(x,y),我们要看的其实是在生成树上x到y的路径上是否存在在某个奇环内的边(“奇环”指长度为奇数的环)。
于是问题转化成看一条边是否在奇环中,一个很直观的想法是,对于一个强连通分量,如果在这个强连通分量中存在一条在奇环中的边,那么所有在强连通分量里的边都是存在于某一个奇环中的。
那么如何在一个强连通分量里找到是否有在奇环中的边呢?我们对这个图做tarjan,对于一条虚边(u,v)如果dep[u]与dep[v]的奇偶性相同(dep[u]表示u在树中的深度),那么u到v的路径上的边都是在奇环中的。
于是我们可以得到每条边是否存在于奇环中,问题就变得很简单了。
对于一个询问(x,y)如果dep[x]和dep[y]奇偶性不同,那么是yes的
否则如果在x到y的路径上存在有在奇环中的边,那么也是yes的,这个可以通过预处理出点到根节点的路径上的这种边的个数得到。
再否则就只有no了。

注意:弹栈要在退栈的时候弹。

  1. const int N=100000+10;
  2. const int D=20;
  3. int n,m,k,tp,idx;
  4. int head[N],d[N],fa[N][D+2],dfn[N],low[N],sta[N],odd[N],s[N],vis[N];
  5. struct edge{
  6. int v,nxt;
  7. }e[N<<1];
  8. void adde(int u,int v){
  9. e[k].v=v;
  10. e[k].nxt=head[u];
  11. head[u]=k++;
  12. }
  13. void tarjan(int u,int fath){
  14. d[u]=d[fath]+1;fa[u][0]=fath;
  15. dfn[u]=low[u]=++idx;sta[++tp]=u;
  16. for(int i=head[u];i!=-1;i=e[i].nxt){
  17. int v=e[i].v;
  18. if(!dfn[v]){
  19. tarjan(v,u);
  20. low[u]=min(low[u],low[v]);
  21. }
  22. else if(v!=fath){
  23. if((d[u]&1)==(d[v]&1)) odd[u]=1;
  24. low[u]=min(low[u],dfn[v]);
  25. }
  26. }
  27. if(dfn[u]==low[u]){
  28. int pos=tp,w=0;
  29. while(sta[pos]!=u) w|=(odd[sta[pos--]]);
  30. if(w==1) {
  31. while(sta[tp]!=u) s[sta[tp--]]++;
  32. }
  33. else tp=pos-1;//!!不能再忘else了!!!!
  34. }
  35. }
  36. int Lca(int u,int v){
  37. if(d[u]<d[v]) swap(u,v);
  38. for(int i=D;i>=0;--i){
  39. if(d[fa[u][i]]>=d[v]) u=fa[u][i];
  40. }
  41. if(u==v) return u;
  42. for(int i=D;i>=0;--i){
  43. if(fa[u][i]!=fa[v][i]){
  44. u=fa[u][i];
  45. v=fa[v][i];
  46. }
  47. }
  48. if(fa[u][0]==fa[v][0]) return fa[u][0];
  49. return -1;
  50. }
  51. void dfs(int u,int fath){
  52. for(int i=head[u];i!=-1;i=e[i].nxt){
  53. int v=e[i].v;
  54. if(fa[v][0]==u){
  55. vis[v]=1;
  56. s[v]+=s[u];
  57. dfs(v,u);
  58. }
  59. }
  60. }
  61. int a,b,q;
  62. int main(){
  63. // freopen("a.txt","r",stdin);
  64. memset(head,-1,sizeof(head));
  65. n=read();m=read();
  66. for(int i=1;i<=m;++i){
  67. a=read();b=read();
  68. adde(a,b);adde(b,a);
  69. }
  70. for(int i=1;i<=n;++i){
  71. if(!dfn[i]){
  72. tarjan(i,i);
  73. }
  74. }
  75. for(int i=1;i<=D;++i){
  76. for(int j=1;j<=n;++j){
  77. fa[j][i]=fa[fa[j][i-1]][i-1];
  78. }
  79. }
  80. for(int i=1;i<=n;++i){
  81. if(fa[i][0]==i){
  82. dfs(i,i);
  83. }
  84. }
  85. q=read();
  86. while(q--){
  87. a=read();b=read();
  88. int l=Lca(a,b);
  89. if(l==-1) {puts("No");continue;}
  90. if(((d[a]+d[b]-2*d[l])&1)==1) {puts("Yes");continue;}
  91. if(s[a]+s[b]>2*s[l]) {puts("Yes");continue;}
  92. puts("No");
  93. }
  94. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注