【Ynoi2011】成都七中【树论】【点分树】【离线】【树状数组】
題意:給一棵樹,點(diǎn)有顏色,qqq 次詢問,每次給定 l,r,xl,r,xl,r,x ,求只保留編號(hào)在 [l,r][l,r][l,r] 中的點(diǎn)時(shí)點(diǎn) xxx 所在連通塊的顏色數(shù)。
所有數(shù) ≤105\leq 10^5≤105
題目背景好評(píng)
首先所有顏色不同的話就是數(shù)連通塊大小,先想想這個(gè)怎么做。
然后不會(huì)做,拜拜了您嘞
考察所求的 xxx 所在連通塊在點(diǎn)分治中的過程,這個(gè)連通塊一直是完整的直到一個(gè)分治中心踩到了這個(gè)連通塊中的一個(gè)點(diǎn)。建出點(diǎn)分樹后,我們預(yù)處理每個(gè)點(diǎn) 與所有點(diǎn)分樹上的祖先在原樹上的路徑經(jīng)過的點(diǎn)編號(hào)的最小值與最大值,然后每個(gè)詢問把 xxx 暴力跳祖先就可以找到這個(gè)點(diǎn)。
這個(gè)點(diǎn)點(diǎn)分樹上的子樹的點(diǎn)包含了所求的連通塊,且這個(gè)點(diǎn)在連通塊內(nèi)。對(duì)于子樹內(nèi)的點(diǎn),它在連通塊內(nèi)當(dāng)且僅當(dāng)?shù)阶訕涞母穆窂降木幪?hào)范圍被詢問區(qū)間完全包含。所以對(duì)每個(gè)點(diǎn) dfs 一遍子樹,然后就是喜聞樂見的主對(duì)角線矩形數(shù)顏色問題。
把詢問離線(這道題里面本來就是離線的)掛在右端點(diǎn)上,然后移動(dòng)右端點(diǎn),維護(hù)每種顏色的點(diǎn)的左端點(diǎn)的最大值,樹狀數(shù)組上加一下就可以了。
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <algorithm> #define MAXN 100005 using namespace std; const int INF=0x7fffffff; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } int col[MAXN]; struct node{int l,r,val;}; //ancestor: val=the index of the ancestor //son: val=the color of the son //query: val=the index of the query vector<int> e[MAXN]; vector<node> p[MAXN],s[MAXN],q[MAXN]; int rt,siz[MAXN],maxp[MAXN],vis[MAXN]; void findrt(int u,int f,int sum) {siz[u]=1,maxp[u]=0;for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f){findrt(e[u][i],u,sum);siz[u]+=siz[e[u][i]];maxp[u]=max(maxp[u],siz[e[u][i]]);}maxp[u]=max(maxp[u],sum-siz[u]);if (maxp[u]<maxp[rt]) rt=u; } void dfs(int u,int f,int l,int r) {p[u].push_back((node){l,r,rt});s[rt].push_back((node){l,r,col[u]});siz[u]=1;for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]&&e[u][i]!=f){dfs(e[u][i],u,min(l,e[u][i]),max(r,e[u][i]));siz[u]+=siz[e[u][i]];} } void build() {vis[rt]=1;dfs(rt,0,rt,rt);int u=rt;for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]){rt=0,findrt(e[u][i],0,siz[e[u][i]]);build();} } const int N=1e5; struct BIT {int s[MAXN];inline int lowbit(const int& x){return x&-x;}inline void modify(int x,int v){for (;x<=N;s[x]+=v,x+=lowbit(x));}inline int query(int x,int ans=0){for (;x;ans+=s[x],x-=lowbit(x));return ans;} }bit; int mx[MAXN]; vector<node> tf[MAXN],tq[MAXN]; vector<int> lis; int ans[MAXN]; int main() {maxp[0]=INF;int n,m;n=read(),m=read();for (int i=1;i<=n;i++) col[i]=read();for (int i=1;i<n;i++) {int u,v;u=read(),v=read();e[u].push_back(v),e[v].push_back(u);}findrt(1,0,n),build();for (int T=1;T<=m;T++){int l,r,x;l=read(),r=read(),x=read();for (int i=0;i<(int)p[x].size();i++)if (l<=p[x][i].l&&p[x][i].r<=r){q[p[x][i].val].push_back((node){l,r,T});break;}}for (int u=1;u<=n;u++){lis.clear();for (int i=0;i<(int)s[u].size();i++)tf[s[u][i].r].push_back(s[u][i]),lis.push_back(s[u][i].r);for (int i=0;i<(int)q[u].size();i++)tq[q[u][i].r].push_back(q[u][i]),lis.push_back(q[u][i].r);sort(lis.begin(),lis.end());lis.erase(unique(lis.begin(),lis.end()),lis.end());for (int t=0;t<(int)lis.size();t++){int r=lis[t];for (int i=0;i<(int)tf[r].size();i++)if (tf[r][i].l>mx[tf[r][i].val]){if (mx[tf[r][i].val]) bit.modify(mx[tf[r][i].val],-1);bit.modify(mx[tf[r][i].val]=tf[r][i].l,1);}for (int i=0;i<(int)tq[r].size();i++)ans[tq[r][i].val]=bit.query(r)-bit.query(tq[r][i].l-1);}for (int i=0;i<(int)s[u].size();i++){if (mx[s[u][i].val]) bit.modify(mx[s[u][i].val],-1);mx[s[u][i].val]=0;}for (int i=0;i<(int)lis.size();i++) tf[lis[i]].clear(),tq[lis[i]].clear();}for (int i=1;i<=m;i++) printf("%d\n",ans[i]);return 0; }總結(jié)
以上是生活随笔為你收集整理的【Ynoi2011】成都七中【树论】【点分树】【离线】【树状数组】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哺乳期能减肥吗减肥会不会对宝宝不好
- 下一篇: 【十二省联考2019】字符串问题【后缀自