1. 程式人生 > >LOJ #2013「SCOI2016」幸運數字

LOJ #2013「SCOI2016」幸運數字

時限為什麼這麼大啊

明擺著放多$ log$的做法過啊$QAQ$

LOJ #2013


題意

有$ Q$次詢問,每次詢問樹上一條鏈,點有點權,你需要選擇一些鏈上的點使得異或和儘量大

點數$ \leq 2*10^4$ 詢問數$ \leq 2*10^5$ 值域不超過$ 2^{64}$


$ Solution$

直接點分

把詢問用$ vector$掛在當前點分中心上

計算一個點的時候 

遞迴計算它統率的子樹,在每個點掛上從自己到根的線性基,

每次相當於繼承父親的線性基並插入一個數

然後將詢問分成兩類

不過當前點分中心的:下放到之後的點分計算

經過當前點分中心的:每次進行一次線性基合併然後求線性基最大值

總複雜度$ O(m·60^2+n·60·log \ n)$


$My \ code$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define ull unsigned long long 
#define M 40010
#define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout)
#define
rt register int #define l putchar('\n') #define ll long long #define r read() using namespace std; inline ll read(){ ll x = 0; char zf = 1; char ch = getchar(); while (ch != '-' && !isdigit(ch)) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (isdigit(ch)) x = x * 10
+ ch - '0', ch = getchar(); return x * zf; } void write(ull y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ull y){write(y);putchar('\n');} int k,m,n,x,y,z,cnt;ull ans[200010]; struct xxj{//線性基 #define sz 60 ull a[sz+1]; xxj(){memset(a,0,sizeof(a));} void insert(ull x){ for(rt i=sz;x;i--)if(x>>i&1){ if(!a[i])return a[i]=x,void(); x^=a[i]; } } bool check(const ull x){ for(rt i=sz;i>=0;i--)if(x>>i&1)if(!a[i])return 1; return 0; } void rebuild(){ for(rt i=sz;i>=0;i--)if(a[i]) for(rt j=i-1;j>=0;j--)if(a[j]>>i&1)a[j]^=a[i]; } ull Max(){ ull ret=0; for(rt i=sz;i>=0;i--)if((ret^a[i])>ret)ret^=a[i]; return ret; } ull Min(){ for(rt i=0;i<=sz;i++)if(a[i])return a[i]; return 0; } ull kth(ull rk){ rebuild();ull ret=0; for(rt i=0,j=0;i<=sz;i++){ while(j<=sz&&!a[j])j++; if(rk>>i&1){ if(j>sz)return 0; ret^=a[j]; }j++; } return ret; } }; xxj merge(const xxj x,const xxj y){ xxj ret=y; for(rt i=sz;i>=0;i--)if(x.a[i])ret.insert(x.a[i]); return ret; } #undef sz struct query{ int x,y,id; }; vector<query>ask[40010]; int nowmin,all,size[20010],Root,troot; int F[M],L[M],N[M],a[M];ull v[M];bool vis[M]; void add(int x,int y){ a[++k]=y; if(!F[x])F[x]=k; else N[L[x]]=k; L[x]=k; } void getroot(int x,int pre){ size[x]=1;int maxsize=0; for(rt i=F[x];i;i=N[i])if(!vis[a[i]]&&a[i]!=pre){ getroot(a[i],x); size[x]+=size[a[i]]; maxsize=max(maxsize,size[a[i]]); } maxsize=max(maxsize,all-size[x]); if(maxsize<nowmin)nowmin=maxsize,Root=x; } int color[M]; void dfs_color(int x,int pre,int col){ color[x]=col; for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]])dfs_color(a[i],x,col); } xxj c[20010]; void dfs_calc(int x,int pre){ if(x==pre)memset(c[x].a,0,sizeof(c[x].a));else c[x]=c[pre]; c[x].insert(v[x]); for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]])dfs_calc(a[i],x); } void calc(int x){ vis[x]=1;color[x]=233333+x; for(rt i=F[x];i;i=N[i])if(!vis[a[i]])dfs_color(a[i],x,a[i]); dfs_calc(x,x); for(auto i:ask[x]){ if(color[i.x]!=color[i.y]) ans[i.id]=max(ans[i.id],merge(c[i.x],c[i.y]).Max()); } const int ls=all; for(auto i:ask[x])if(color[i.x]==color[i.y])ask[color[i.x]+20000].push_back(i); for(rt i=F[x];i;i=N[i])if(!vis[a[i]]){ if(size[a[i]]>size[x])all=nowmin=ls-size[x];else all=nowmin=size[a[i]]; getroot(a[i],x);ask[Root].clear(); ask[Root]=ask[a[i]+20000];ask[a[i]+20000].clear(); calc(Root); } } int main(){ n=r;m=r; for(rt i=1;i<=n;i++)v[i]=r; for(rt i=1;i<n;i++){ x=r;y=r; add(x,y); add(y,x); } nowmin=all=n;getroot(1,1);troot=Root; for(rt i=1;i<=m;i++){ x=r;y=r; if(x==y)ans[i]=v[x];else ask[troot].push_back({x,y,i}); } calc(troot); for(rt i=1;i<=m;i++)writeln(ans[i]); return 0; }