1. 程式人生 > >BZOJ3531-[Sdoi2014]旅行

BZOJ3531-[Sdoi2014]旅行


題解:
正常的樹鏈剖分,但由於顏色的限制,不能只開一棵線段樹,我們可以對每個顏色都開一棵線段樹,但這樣空間不行,我們只要建實時開點線段樹,就可以了。
對於詢問,只要在那個顏色的線段樹上詢問就好了。
Code

#include<iostream>
#include<cstdio>
#include<cstring>
#define M 10000005
#define N 100005
using namespace std;
int n,m,cnt,place,size;
int s[17],w[N],c[N],root[N],fa[N][17],deep[N],vis[N];
int
pl[N],belong[N],son[N],head[N],ls[M],rs[M],mx[M],sum[M]; struct data { int vet,next; }edge[N*2]; void ins(int u,int v) { edge[++cnt].vet=v; edge[cnt].next=head[u]; head[u]=cnt; } void dfs1(int x) { vis[x]=1;son[x]=1; for(int i=1;i<=16;i++) if(s[i]<=deep[x])fa[x
][i]=fa[fa[x][i-1]][i-1]; else break; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].vet; if(vis[v])continue; deep[v]=deep[x]+1; fa[v][0]=x; dfs1(v); son[x]+=son[v]; } } void dfs2(int x,int chain) { place++; pl[x]=place; belong[x
]=chain; int k=0; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].vet; if(deep[v]>deep[x]&&son[v]>son[k]) k=v; } if(k)dfs2(k,chain); for(int i=head[x];i;i=edge[i].next) { int v=edge[i].vet; if(deep[v]>deep[x]&&v!=k) dfs2(v,v); } } int lca(int x,int y) { if(deep[x]<deep[y])swap(x,y); int t=deep[x]-deep[y]; for(int i=0;i<=16;i++) if(s[i]&t)x=fa[x][i]; for(int i=16;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; if(x==y)return x; return fa[x][0]; } void change(int &k,int l,int r,int x,int num) { if(!k)k=++size; if(l==r) { mx[k]=sum[k]=num; return; } int mid=(l+r)>>1; if(x<=mid)change(ls[k],l,mid,x,num);else change(rs[k],mid+1,r,x,num); mx[k]=max(mx[ls[k]],mx[rs[k]]); sum[k]=sum[ls[k]]+sum[rs[k]]; } int askmx(int k,int l,int r,int x,int y) { if(!k)return 0; if(l==x&&y==r)return mx[k]; int mid=(l+r)>>1; if(y<=mid)return askmx(ls[k],l,mid,x,y);else if(x>mid)return askmx(rs[k],mid+1,r,x,y);else return max(askmx(ls[k],l,mid,x,mid),askmx(rs[k],mid+1,r,mid+1,y)); } int asksum(int k,int l,int r,int x,int y) { if(!k)return 0; if(l==x&&y==r)return sum[k]; int mid=(l+r)>>1; if(y<=mid)return asksum(ls[k],l,mid,x,y);else if(x>mid)return asksum(rs[k],mid+1,r,x,y);else return asksum(ls[k],l,mid,x,mid)+asksum(rs[k],mid+1,r,mid+1,y); } int solvemx(int c,int x,int f) { int mx=0; while(belong[x]!=belong[f]) { mx=max(mx,askmx(root[c],1,n,pl[belong[x]],pl[x])); x=fa[belong[x]][0]; } mx=max(mx,askmx(root[c],1,n,pl[f],pl[x])); return mx; } int solvesum(int c,int x,int f) { int sum=0; while(belong[x]!=belong[f]) { sum+=asksum(root[c],1,n,pl[belong[x]],pl[x]); x=fa[belong[x]][0]; } sum+=asksum(root[c],1,n,pl[f],pl[x]); return sum; } int main() { s[0]=1; for(int i=1;i<=16;i++) s[i]=(s[i-1]<<1); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&c[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); ins(u,v); } dfs1(1);dfs2(1,1); for(int i=1;i<=n;i++) change(root[c[i]],1,n,pl[i],w[i]); for(int i=1;i<=m;i++) { char ch[5];scanf("%s",ch); int x,y; scanf("%d%d",&x,&y); if(ch[0]=='C') { if(ch[1]=='C') { change(root[c[x]],1,n,pl[x],0); c[x]=y; change(root[c[x]],1,n,pl[x],w[x]); }else { change(root[c[x]],1,n,pl[x],y); w[x]=y; } }else { int f=lca(x,y); if(ch[1]=='S') { int t=solvesum(c[x],x,f)+solvesum(c[x],y,f); if(c[x]==c[f])t-=w[f]; printf("%d\n",t); }else printf("%d\n",max(solvemx(c[x],x,f),solvemx(c[x],y,f))); } } return 0; }

相關推薦

bzoj3531[Sdoi2014]旅行

輸入 mes for gpo 路徑 left long long bzoj3 不變 3531: [Sdoi2014]旅行Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 2640 Solved: 1142[Submit][St

BZOJ3531-[Sdoi2014]旅行

題解: 正常的樹鏈剖分,但由於顏色的限制,不能只開一棵線段樹,我們可以對每個顏色都開一棵線段樹,但這樣空間不行,我們只要建實時開點線段樹,就可以了。 對於詢問,只要在那個顏色的線段樹上詢問就好了。 Code:Code: #include<ios

BZOJ 3531 SDOI2014 旅行 樹鏈剖分

can algorithm 一個點 復雜度 顏色 正常 track log case 題目大意:給定一棵樹,每一個點有一個權值和一個顏色。多次改變一些點的權值和顏色,多次求一條路徑上與起點和終點顏色同樣的點的權值和以及權&#

【題解】SDOI2014旅行

一點 com col new 旅行 題解 cnp || name 洛谷P3313 大概是一道樹鏈剖分的裸題。可以看出如果不是查詢相同宗教的這一點,就和普通的樹鏈剖分毫無兩樣了。所以針對每一個宗教都單獨開一棵線段樹,變成單點修改+區間查詢。只不過宗教數目很多,空間消耗太大所以

BZOJ 3531 [Sdoi2014]旅行

end har change check cmp pan ostream father continue 題解: 解法1: 樹鏈剖分一下,對每條鏈建立一顆Splay 以宗教為第一關鍵字,深度為第二關鍵字建立 查詢相當於Splay的一個區間 修改相當於刪除一個節點,加入一個節

洛谷 P3313 [SDOI2014]旅行 解題報告

HA 發生 間隔 如果 節省空間 query tro oid 問題 P3313 [SDOI2014]旅行 題目描述 S國有N個城市,編號從1到N。城市間用N-1條雙向道路連接,滿足從一個城市出發可以到達其它所有城市。每個城市信仰不同的宗教,如飛天面條神教、隱形獨角獸教、絕地

洛谷 P3313 [SDOI2014]旅行 樹鏈剖分+動態開點線段樹

P3313 這個題要根據每個城市信仰的宗教建線段樹,但是這樣的話最多會有1e5個線段樹,所以要動態開點(其實就是主席樹思想),先把樹用重鏈剖分,剖出來每個點有線上段樹上對應的區間,所以線段樹共用這一套區間,問題就簡單了,至於修改城市的宗教,只需把原來宗教那個線段樹的對應區間清0,在修改後宗教

luogu_P3313 [SDOI2014]旅行

傳送門 Solution 第二次學習可持久化線段樹 打了一道裸題來練習一下…… 對於每個宗教都可以開一個主席樹 基礎操作 樹剖lca Code  #include<bits/stdc++.h> #define ll long

BZOJ 3531: [Sdoi2014]旅行

這題就是樹鏈剖分,對於多種宗教就開多個線段樹,動態開點就好了。 記得卡記憶體 然而一個城市的宗教變了之後還能在變回來,導致我調了一下午。。。 #include<cstdio> #include<cstring> #include<algorithm> #include

[SDOI2014]旅行

P3313 [SDOI2014]旅行 思路 有點噁心咯 每個信仰開一顆線段樹記錄 修改或者查詢的時候去那一顆信仰線段樹中查詢就好 必須動態開點線段樹 沒有區間修改還算好寫 錯誤 查詢跳鏈寫錯了 #include <bits/stdc++.h> #define FOR(i,a,b) for

|BZOJ 3531|樹鏈剖分|動態開點線段樹|[Sdoi2014]旅行

樹剖以後每個宗教建立一棵線段樹,節點太多用傳統方法開陣列肯定不行,這裡進行改進,使用了動態開點線段樹,即需要這個點再開這個點。 #include<cstdio> #include<cstring> #include<alg

【[SDOI2014]旅行

聽說這是動態開點主席樹的板子題,但是發現我還不會,於是就來寫一寫 其實跟主席樹一個樣子的 這裡就是存個板子吧 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

bzoj3531SDOI2014旅行

pop data- con time mono bzoj3531 www family swa 3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 850 Solved

CodeVS 1036 商務旅行

height 祖先 memset 商務 最近公共祖先 pri nbsp nsh return 最近一邊轉c++一邊學算法,因為GDOI好像考了LCA,不會寫怎麽辦呢?(當然是爆零得到教訓後再來學啊..) 題目大意:給一棵樹,求經過給定結點的最小費用。。 算法:帶權LCA?倍

【BZOJ1570】[JSOI2008]Blue Mary的旅行 動態加邊網絡流

efi 一次 第一次 dfs name jsoi2008 網絡公司 data cstring 【BZOJ1570】[JSOI2008]Blue Mary的旅行 Description 在一段時間之後,網絡公司終於有了一定的知名度,也開始收到一些訂單,其中最大的一宗來自B

洛谷P1027 Car的旅行路線 計算幾何 圖論最短路

name ani 但是 ret sqrt bsp include struct == 題意 求某城到某城的最小花費 一個城中有四個機場,一個城中的機場相互可達,用公路到達,但是不同城的公路的單位路程的費不同,兩個不同城的機場(我不知道相同城可不可以)可以通過機場到達,且飛機

[NOIP2012] 開車旅行

[0 spa play long b+ pac deque 其中 include 【題目描述】 小A 和小B決定利用假期外出旅行,他們將想去的城市從1到N 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i的海拔高度為Hi,城市 i 和

BZOJ 2157 旅行(樹鏈剖分碼農題)

tac pragma code vector zoj pla none close tag 寫了5KB,1發AC。。。 題意:給出一顆樹,支持5種操作。 1.修改某條邊的權值。2.將u到v的經過的邊的權值取負。3.求u到v的經過的邊的權值總和。4.求u到v的經過的邊的權值最

一個人的旅行 HDU杭電2066【dijkstra算法 || SPFA】

個數 strong -s stdio.h rip include tom trac 第一次 http://acm.hdu.edu.cn/showproblem.php?pid=2066 Problem Description 盡管草兒是個路癡(就是在杭電待了一

【NOIP2012】開車旅行

algo sam time mat row 不同的 blog -- 但是 Description 小A 和小B決定利用假期外出旅行,他們將想去的城市從1到N 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i的海拔高度為Hi,城市