作者部落格:
正解:線性基+鏈剖+線段樹
解題報告:
考慮直接用線段樹維護線性基,構出來之後,每次詢問都只需要在樹上跳就好了。
線性基可以暴力合併,合併的複雜度是$o(log^2n)$。
最後查詢一遍合併得到的最終線性基就可以了。
$upd$:
考慮樹分治做法:我們把詢問離線下來,然後每次分治的時候$dfs$求出重心到所有的點,路徑上的線性基。
接著就看一下所有的詢問,如果詢問的兩個點分居不同子樹中,那麼直接回答詢問就好了,時間複雜度:$o(60*nlogn+q*60*60)$,而且線性基裡面加$break$還有各種優化之後,遠遠不到上界…
貼一發簡單暴力無腦的解法一的**:
//it is made by ljh2000//有志者,事竟成,破釜沉舟,百二秦關終屬楚;苦心人,天不負,臥薪嘗膽,三千越甲可吞吳。
#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
typedef long double lb;
typedef complexc;
const double pi = acos(-1);
const int maxn = 40011;
const int maxm = 400011;
int n,m,ecnt,first[maxn],to[maxm],next[maxm],top[maxn],deep[maxn],father[maxn],size[maxn],son[maxn],id[maxn],pre[maxn],flag,ql,qr;
ll val[maxn],lin,ans;
struct nodea[maxn*3],tmp;
inline void link(int x,int y)
inline int getint()
inline ll getll()
inline void dfs(int x,int fa)
}inline void dfs2(int x,int fa)
for(int i=first[x];i;i=next[i])
}inline node merge(node q,node qq)
lin^=qq.s[j];
} }return qq;
}inline void build(int root,int l,int r)
a[root].top=1;
return ;
} int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1;
build(lc,l,mid); build(rc,mid+1,r);
a[root]=merge(a[lc],a[rc]);
}inline void query(int root,int l,int r)
int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1;
if(ql<=mid) query(lc,l,mid); if(qr>mid) query(rc,mid+1,r);
}inline void lca(int x,int y)
}int main()
//有志者,事竟成,破釜沉舟,百二秦關終屬楚;苦心人,天不負,臥薪嘗膽,三千越甲可吞吳。
BZOJ4568 Scoi2016 幸運數字
樹上查兩點間最大異或和 樹倍增,每個點維護向上2 k個點的線性基,然後在查lca的時候合併 關於點權維護倍增略蛋疼 合併線性基的時候就直接把乙個線性基里的插到另乙個裡 複雜度o m log n log 2inf 合併的時候加點優化可以降掉乙個loginf 接下來bb一些有關線性基和最大異或和的東西 ...
BZOJ 4568 Scoi2016 幸運數字
題目大意 給你一顆樹,多個詢問,問你樹上任意兩點的路徑上選任意幾個點使得異或和最大。我是參考的claris大神的 點分治,對於詢問在兩個子樹間或者有乙個在重心上的進行回答,否則把問題用鍊錶接到詢問點所在的子樹上。具體方法可以選中重心都對每個子樹染色,染為這個子樹的根節點。在子樹處理問題之前一定要記住...
BZOJ 4568 Scoi2016 幸運數字
可以合併的東西都是人類互相傷害的 參照cogs上採礦那道題 可以用樹剖維護線性基,複雜度q logn 2 logw 2 顯然會t。考慮到沒有修改 用點分治離線來做 乙個詢問如果經過當前分治根,則立即處理並不再下傳,否則下傳到相應子樹去做 複雜度nlognlogw qlogwlogw include ...