吼题啊

刚开始看上去又以为是LCT啥子的。

后来发现,TM是个图。

然后果断准备放弃,突然发现只有N个点N条边。

woc,这不就一个基环树上树链剖分吗。。。

关于基环树问题,相信大家都一定很有经验了吧,用个并查集找出多的边,然后把图分成一棵树和一条边,然后树上就树上做,多出来的边就可以另外处理。

关于边权转点权,直接在查询的最后减去LCA的点权就OK了,其他当成点权处理。

关于线段树,这个大家都会改吧。。。

关于修改操作,直接找出相应的点权,然后修改就行了,找点权记得先边的编号乘2

总之还是很简单的

下面可以看看代码注释:

#include<bits/stdc++.h>
#define maxn 4000001
#define L(x) (x<<1)
#define R(x) ((x<<1)|1)
using namespace std;
int tree[maxn],tag[maxn];
int rev[maxn],dep[maxn],size[maxn],seg[maxn],top[maxn],son[maxn],father[maxn];
int n,m,root,x,y,z,a[maxn],visx[maxn],visy[maxn],tot,mode;
int cnt,from[maxn],to[maxn],Next[maxn],head[maxn];
int Gx,Gy,Gz,Gd;
int fa[maxn],X[maxn],Y[maxn],Z[maxn];
int find(int x){
if(fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
bool merge(int x,int y){
int i=find(x),j=find(y);
if(i==j)return false;
fa[i]=j;return true;
}
void add(int x,int y){
cnt++;
from[cnt]=x;to[cnt]=y;
Next[cnt]=head[x];head[x]=cnt;
}
void update(int node,int begin,int end,int x,int y,int val){
if(begin>y||end<x)return;
if(begin>=x&&end<=y){
tree[node]=val;
return;
}else{
int mid=(begin+end)>>1;
if(x<=mid)update(L(node),begin,mid,x,y,val);
if(y>mid) update(R(node),mid+1,end,x,y,val);
tree[node]=tree[L(node)]+tree[R(node)];
}
}
int query(int node,int begin,int end,int x,int y){
if(begin>=x&&end<=y){
return tree[node];
}else{
int mid=(begin+end)>>1,sum=0;
if(x<=mid)sum+=query(L(node),begin,mid,x,y);
if(y>mid) sum+=query(R(node),mid+1,end,x,y);
return sum;
}
}
int dfs1(int x){
size[x]=1;
dep[x]=dep[father[x]]+1;
for(int i=head[x];i!=-1;i=Next[i]){
int v=to[i],big=0;
if(father[x]==v)continue;
father[v]=x;
big=dfs1(v);
size[x]+=big;
if(big>size[son[x]])son[x]=v;
}
return size[x];
}
void dfs2(int x){
if(son[x]){
seg[son[x]]=++seg[0];
top[son[x]]=top[x];
rev[seg[0]]=son[x];
dfs2(son[x]);
}
for(int i=head[x];i!=-1;i=Next[i]){
int v=to[i];
if(!top[v]){
seg[v]=++seg[0];
top[v]=v;
rev[seg[0]]=v;
dfs2(v);
}
}
}
int linkquery(int x,int y){
int fx=top[x],fy=top[y],ans=0;
while(fx!=fy){
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
ans+=query(1,1,seg[0],seg[fx],seg[x]);
x=father[fx];fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
ans+=query(1,1,seg[0],seg[x],seg[y]);
ans-=query(1,1,seg[0],seg[x],seg[x]);
return ans;
}
void change(int x,int y){ //修改边权
x*=2; //记得乘2
x=dep[from[x]]>dep[to[x]]?from[x]:to[x]; //因为边权钦定的是深度大的点
update(1,1,seg[0],seg[x],seg[x],y); //直接改
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);root=1;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&z);
if(merge(x,y)){add(x,y),add(y,x);}
else Gx=x,Gy=y,Gz=z,Gd=i,cnt+=2; //并查集判多的边
X[i]=x;Y[i]=y;Z[i]=z;
}
dfs1(root);
seg[root]=++seg[0];
rev[seg[0]]=root;
top[root]=root;
dfs2(root);
for(int i=1;i<=n;i++)if(Gd!=i)change(i,Z[i]); //因为本人懒得写build,所以这样写
for(int i=1;i<=m;i++){
scanf("%d%d%d",&mode,&x,&y);
if(mode==1){
if(x==Gd)Gz=y; //如果是多余的边就直接改
else change(x,y); //不然就另外改
}else{
int ans;
ans=linkquery(x,y); //第一种情况,不经过多余的边
ans=min(ans,Gz+min(linkquery(x,Gx)+linkquery(Gy,y),linkquery(x,Gy)+linkquery(Gx,y))); //第二种情况,经过多余的边
printf("%d\n",ans);
}
}
}

最新文章

  1. 《ASP.NET Web API 2框架揭秘》样章(PDF版本)
  2. JVM 参数分配
  3. C#中==与Equals方法的区别
  4. oracle 数据库时间类型为字符串 时间范围大小查询
  5. 【poi】用POI新建一个xlsx文件【或者说将数据存入到xlsx中】/【将数据从xlsx中获取到项目中】
  6. typedef struct trx_struct trx_t;
  7. C#下利用高精度计时器进行计时操作
  8. c++11 Chrono时间库
  9. 基于Oracle OCI的数据访问C语言接口ORADBI .
  10. CSS3实现jquery的特效
  11. Memcached报错
  12. .net中除去IList中的多余项
  13. Nginx 介绍和安装
  14. string 与wstring 的转换
  15. docker容器自动退出的问题
  16. Ubuntu 16.04 安装Gitlab
  17. Could not find package vendor/name in a version matching v-Number 是坑!
  18. centos7.6编译安装php7.2.11及redis/memcached/rabbitmq/openssl/curl等常见扩展
  19. C# RSA加解密与验签,AES加解密,以及与JAVA平台的密文加解密
  20. The First Day Of Cnblogs

热门文章

  1. 对图书管理系统5W1H的分析
  2. 具体的client-server通信模型以及最为常用的通信模式
  3. JDK8;HashMap:再散列解决hash冲突 ,源码分析和分析思路
  4. AgileReview 代码检视工具使用
  5. maven的背景
  6. Nexus-vPC理论
  7. 夯实Java基础(二十五)——JDBC使用详解
  8. Update(Stage4):Structured Streaming_介绍_案例
  9. StaticLinkList(静态链表)
  10. centos610最小安装之后 后续设置