bzoj 2157 旅游

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2157

明明是裸LCT板子……

注意pshp的那个地方!原以为把0~n的mx、mn都赋好初值就能随便弄了,仔细想想要用的是val!

  而且还是既用在max里又用在min里,故不能赋初值来怎样,应当分类讨论!

关于变成相反数的操作,原来也是打标记!而且标记的含义和线段树的一样,表示自己已经操作过、要给孩子操作。这样才能保证query的正确。

  可是自己那种dfs来当即弄成相反数的做法为什么不行???

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2e4+5,M=4e4+5;
int n,m,pre[M],sum[M],val[M],mx[M],mn[M],c[M][2],stack[M],top,sta[M];
bool rev[M];
bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;}
void pshp(int x)
{
  int ls=c[x][0],rs=c[x][1];
  sum[x]=val[x]+sum[ls]+sum[rs];
  mx[x]=max(mx[ls],mx[rs]);
  mn[x]=min(mn[ls],mn[rs]);
  if(x>n)mx[x]=max(val[x],mx[x]),mn[x]=min(val[x],mn[x]);
//  mx[x]=max(val[x],max(mx[ls],mx[rs]));
//  mn[x]=min(val[x],min(mn[ls],mn[rs]));
}
void reverse(int x)
{
  if(rev[x])
    {
      rev[c[x][0]]^=1;rev[c[x][1]]^=1;
      swap(c[x][0],c[x][1]);
      rev[x]=0;
    }
}
void rotate(int x)
{
  int y=pre[x],z=pre[y],d=(x==c[y][1]);
  if(!isroot(y))c[z][y==c[z][1]]=x;
  pre[x]=z;pre[y]=x;
  c[y][d]=c[x][!d];pre[c[x][!d]]=y;c[x][!d]=y;
  pshp(y);pshp(x);
}
void splay(int x)
{
  stack[top=1]=x;
  for(int t=x;!isroot(t);t=pre[t])stack[++top]=pre[t];
  for(;top;top--)reverse(stack[top]);
  for(;!isroot(x);rotate(x))
    {
      int y=pre[x],z=pre[y];
      if(isroot(y))continue;
      ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y);
    }
}
void access(int x)
{
  for(int t=0;x;c[x][1]=t,pshp(x),t=x,x=pre[x])splay(x);
}
void makeroot(int x)
{
  access(x);splay(x);rev[x]^=1;
}
void query(int x,int y)
{
  makeroot(x);access(y);splay(y);
}
void link(int x,int y)
{
  makeroot(x);pre[x]=y;
}
void dfs(int cr)
{
  val[cr]=-val[cr];
  if(c[cr][0])dfs(c[cr][0]);
  if(c[cr][1])dfs(c[cr][1]);
  pshp(cr);
}
int main()
{
  scanf("%d",&n);int x,y,z;
  mx[0]=-1005;mn[0]=1005;//写在link前
  for(int i=1;i<n;i++)
    {
      scanf("%d%d%d",&x,&y,&z);x++;y++;
      val[i+n]=z;
      link(i+n,x);link(i+n,y);
    }
  char ch[5];
  scanf("%d",&m);
  while(m--)
    {
      scanf("%s%d%d",ch,&x,&y);
      if(ch[0]!=‘C‘)x++,y++,query(x,y);//仅!=‘C‘时++!!!
      if(ch[0]==‘C‘){
    splay(x+n);val[x+n]=y;pshp(x+n);
      }
      else if(ch[0]==‘N‘)dfs(x);
      else if(ch[1]==‘U‘)printf("%d\n",sum[y]);
      else if(ch[1]==‘A‘)printf("%d\n",mx[y]);
      else printf("%d\n",mn[y]);
    }
  return 0;
}

会WA的做法

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2e4+5,M=4e4+5;
int n,m,pre[M],sum[M],val[M],mx[M],mn[M],c[M][2],stack[M],top,sta[M],tp;
bool rev[M],tag[M];
bool isroot(int x){return c[pre[x]][0]!=x&&c[pre[x]][1]!=x;}
void pshp(int x)
{
  int ls=c[x][0],rs=c[x][1];
  sum[x]=val[x]+sum[ls]+sum[rs];
  mx[x]=max(mx[ls],mx[rs]);
  mn[x]=min(mn[ls],mn[rs]);
  if(x>n)mx[x]=max(mx[x],val[x]),mn[x]=min(mn[x],val[x]);//////
//  mx[x]=max(val[x],max(mx[ls],mx[rs]));
//  mn[x]=min(val[x],min(mn[ls],mn[rs]));
}
void tg(int x)
{
    sum[x]=-sum[x];val[x]=-val[x];tag[x]^=1;
    swap(mn[x],mx[x]);mx[x]=-mx[x];mn[x]=-mn[x];
}
void pshd(int x)
{
    int ls=c[x][0],rs=c[x][1];
    if(rev[x])
    {
      rev[ls]^=1;rev[rs]^=1;
      swap(c[x][0],c[x][1]);
      rev[x]=0;
    }
    if(tag[x])
    {
        tag[x]=0;if(ls)tg(ls);if(rs)tg(rs);
    }
}
void rotate(int x)
{
  int y=pre[x],z=pre[y],d=(x==c[y][1]);
  if(!isroot(y))c[z][y==c[z][1]]=x;
  pre[x]=z;pre[y]=x;
  c[y][d]=c[x][!d];pre[c[x][!d]]=y;c[x][!d]=y;
  pshp(y);pshp(x);
}
void splay(int x)
{
  stack[top=1]=x;
  for(int t=x;!isroot(t);t=pre[t])stack[++top]=pre[t];
  for(;top;top--)pshd(stack[top]);    //倒序,标记才能全清除
  for(;!isroot(x);rotate(x))
    {
      int y=pre[x],z=pre[y];
      if(isroot(y))continue;
      ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y);
    }
}
void access(int x)
{
  for(int t=0;x;splay(x),c[x][1]=t,pshp(x),t=x,x=pre[x]);
}
void makeroot(int x)
{
  access(x);splay(x);rev[x]^=1;
}
void query(int x,int y)
{
  makeroot(x);access(y);splay(y);
}
void link(int x,int y)
{
  makeroot(x);pre[x]=y;
}
void chg(int x,int y)
{
    splay(x);val[x]=y;pshp(x);//splay即可,不用makeroot
}
int main()
{
  scanf("%d",&n);int x,y,z;
  mx[0]=-1005;mn[0]=1005;
//  for(int i=0;i<=n;i++)mx[i]=-1005,mn[i]=1005;//
  for(int i=1;i<n;i++)
    {
      scanf("%d%d%d",&x,&y,&z);x++;y++;
      val[i+n]=z;
      link(i+n,x);link(i+n,y);
    }
  char ch[5];
  scanf("%d",&m);
  while(m--)
    {
      scanf("%s%d%d",ch,&x,&y);
      if(ch[0]!=‘C‘)x++,y++,query(x,y);//仅!=‘C‘时++!!!
      if(ch[0]==‘C‘)chg(x+n,y);
      else if(ch[0]==‘N‘)tg(y);
      else if(ch[1]==‘U‘)printf("%d\n",sum[y]);
      else if(ch[1]==‘A‘)printf("%d\n",mx[y]);
      else printf("%d\n",mn[y]);
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/9241785.html

时间: 2024-10-09 07:16:19

bzoj 2157 旅游的相关文章

BZOJ 2157 旅游(动态树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2157 [题目大意] 支持修改边,链上查询最大值最小值总和,以及链上求相反数 [题解] 我们将边转化成点,直接用LCT可以处理以上操作 [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010; int n; co

BZOJ 2157 旅游(树链剖分+线段树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2157 [题目大意] 支持修改边,链上查询最大值最小值总和,以及链上求相反数 [题解] 树链剖分,然后线段树维护线段操作即可. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF=~0U>>1; const

BZOJ 2157 旅游 树链剖分

题目大意:给出一棵树,支持以下操作:1.改变一条边的边权.2.将x到y路径的权值取反.3.查询x到y路径上最大值,最小值和权值和. 思路:好裸的链剖水题啊,唯一麻烦一点地是权值放在了边上,注意一下处理就没问题了.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

【BZOJ】2157: 旅游

http://www.lydsy.com/JudgeOnline/problem.php?id=2157 题解:裸lct不解释.. #include <bits/stdc++.h> using namespace std; struct node *null; struct node { node *c[2], *f; bool flag, rev, tag; int k, sum, mx, mn; bool d() { return f->c[1]==this; } void setc

AC日记——旅游 bzoj 2157

2157 思路: LCT: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 400005 #define INF 0x3f3f3f3f int n,val[maxn],sum[maxn],Max[maxn],Min[maxn],ch[maxn][2]; int rev[maxn],flag[maxn],f[maxn],top,st[maxn],m,cur[maxn],id; inline void in(int &a

【BZOJ 2157】旅游

再水一道模板题,明天就要出发去参加二轮省选了赶紧复习复习模板. 链剖模板题,可是写链剖太麻烦了,还是写lct吧. 但这个lct比较麻烦了,因为边权有正有负,要统计最大值和最小值,这样点权赋为什么值都会妨碍统计. 想了半天,后来发现自己脑抽了,统计的时候特判一下当前点是点还是边不就可以了吗? 裸的模板题调了好久啊,因为后来往原先错误的程序加上上述特判时总是漏这漏那,以后一定要认真思考每个细节确保无误后再开始写代码,这样脑子里有一个清晰的框架,写起来更快,而且不容易出错,大大节省了调试的时间.切忌边

bzoj 2157

链剖...这次的信息存在边上... 调了好久啊QAQ,没有看出连锁错误,对代码的敏感程度还是太差了,老是依赖debug(论NOIP为何会死得那么惨) 1 #include<bits/stdc++.h> 2 #define inc(i,l,r) for(int i=l;i<=r;i++) 3 #define dec(i,l,r) for(int i=l;i>=r;i--) 4 #define link(x) for(edge *j=h[x];j;j=j->next) 5 #de

BZOJ 2157 旅行(树链剖分码农题)

写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v经过的边的权值最小值. 基于边权的树链剖分,放在线段树上变成了区间维护问题了,线段树维护4个量min,max,sum,tag就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include