題目連線:hdu_5589_Tree
題意:給你一棵樹和一些邊值,n個點n-1條邊,一個m,q個詢問,每個詢問讓你輸出在[l,r]區間內任意兩點樹上的路徑的邊權異或的和大於m的點對數。
題解:這題很巧妙,看資料知道要用莫隊,不過如何來處理樹上任意兩點的邊權異或和大於m呢?我們知道,一個數和另一個數異或兩次等於自己,如果我們記錄所有的點都與1這個點的路徑異或和,不就可以得出任意兩點的路徑異或和了嗎,然後如果我們要用莫隊,就要找到增加,刪除的時候答案對應的變化,要支援增加刪除,並且要找比m大的異或值,01字典樹是一個不錯的選擇,我們考慮如果要找比m大的數,那麼在二進位制下,前面的位肯定都相同,後面的某一位m為0,當前數為1才有比m大,我們在將異或和插入字典樹的時候,轉換為二進位制,從高位開始插,每插一位,當前的cnt++,表示在當前位為0或者1的數有一個,刪除的時候就對應cnt--就行了。
詢問:這裡設即將插入的數為節點x到1的節點的異或值為sum,我們要和m相比,因為要找比m大的數,而我們此時插入的都是當前節點到根節點的異或和,這裡我們就要用到貪心的思想,從高位開始找,當m的當前位為1時,此時你只能找字典樹中為與sum當前位異或為1的,如果不找與sum當前位異或為1的那你後面的位無論怎麼找,都不能大於m,要與sum當前位異或為1,當sum的當前位為0,應找1這個子節點,當sum當前位為1,應找0這個子節點,所以就是當m的當前位為1時,下一個子節點應為(sum的當前位^1),當m的當前位為0時,直接加上與sum當前位異或為1的子節點的cnt,因為到這一位的時候,與sum當前位異或為1,那後面位與sum異或完後必然是大於m的,所以直接加上當前與sum異或為1的子節點的cnt就行了,然後我們繼續搜尋與sum當前為異或為0的下一位,和上面一樣,要使與sum當前位異或為0,sum當前位^0=sum當前位。
最後莫隊處理完就是結果了
- #include<cstdio>
- #include<cstring>
- #include<cmath>
- #include<algorithm>
- #define F(i,a,b) for(int i=a;i<=b;i++)
- using namespace std;
- typedef long long LL;
- const int N=;
- int M[],va[N],sqr,n,m,k,x,y,z;
- LL ans[N];
- struct query{
- int l,r,id,sq;
- bool operator<(const query & b)const{
- if(sq==b.sq)return r<b.r;
- return sq<b.sq;
- }
- }q[N];
- //-------------------------樹的處理-----------------
- int g[N],nxt[N<<],w[N<<],v[N<<],eda;
- inline void adg(int x,int y,int z){v[++eda]=y,w[eda]=z,nxt[eda]=g[x],g[x]=eda;}
- void dfs(int u=,int pre=){
- for(int i=g[u];i;i=nxt[i])
- if(v[i]!=pre)va[v[i]]=w[i]^va[u],dfs(v[i],u);
- }
- //----------------字典樹----------------------------
- struct Trie{
- int sum[N*][],cnt[N*],ed,c,mc;
- void init(){ed=cnt[]=,sum[][]=sum[][]=;}
- void insert(int x,int now=){
- for(int i=;i>=;i--){
- c=x>>i&;
- if(!sum[now][c])
- sum[now][c]=++ed,cnt[ed]=,sum[ed][]=sum[ed][]=;
- now=sum[now][c],cnt[now]++;
- }
- }
- void del(int x,int now=){
- for(int i=;i>=;i--)c=x>>i&,now=sum[now][c],cnt[now]--;
- }
- LL ask(int x,int now=,LL ans=){
- for(int i=;i>=;i--){
- c=x>>i&,mc=M[i];
- if(mc)now=sum[now][c^];
- else ans+=cnt[sum[now][c^]],now=sum[now][c];
- if(!now)return ans;
- }
- return ans;
- }
- }tr;
- void modui(){
- sort(q+,q++k);
- int l=,r=;LL ret=;
- F(i,,k){
- while(r<q[i].r)r++,ret+=tr.ask(va[r]),tr.insert(va[r]);
- while(l>q[i].l)l--,ret+=tr.ask(va[l]),tr.insert(va[l]);
- while(r>q[i].r)tr.del(va[r]),ret-=tr.ask(va[r]),r--;
- while(l<q[i].l)tr.del(va[l]),ret-=tr.ask(va[l]),l++;
- ans[q[i].id]=ret;
- }
- }
- int main(){
- while(~scanf("%d%d%d",&n,&m,&k)){
- sqr=(int)sqrt(n);
- for(int ee=;ee<=;ee++)M[ee]=(m>>ee)&;
- memset(g,,sizeof(g)),eda=;
- F(i,,n-)scanf("%d%d%d",&x,&y,&z),adg(x,y,z),adg(y,x,z);
- F(i,,k)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i,q[i].sq=q[i].l/sqr;
- dfs(),tr.init(),modui();
- F(i,,k)printf("%lld\n",ans[i]);
- }
- return ;
- }