很久很久以前,乙個蒟蒻種了一棵會提問的樹,樹有\(n\)個節點,每個節點有乙個權值,現在樹給出\(m\)組詢問,每次詢問兩個值:樹上一組點對\((x,y)\)簡單路徑上不同權值的數量以及權值的\(\max\)為多少
然而某一天毒瘤胖子過來給樹澆了點水,詢問變成了每次求,一組點對\((x,y)\)簡單路徑上的不同權值的數量以及權值的\(mex\)
然而又過了兩天毒瘤袁穩穩也過來給樹澆了點水,詢問變成了每次求若干組點對\((x,y)\)簡單路徑的並集上的不同權值的數量以及權值的\(mex\)(如有疑惑見\(hint\))
然後蒟蒻就菜哭在樹下了qwq並且毫不負責任地把這個問題丟給了剛好路過的你
因為這棵樹受到了兩個毒瘤的祝福,每次詢問受到了加密,記\(lastans\)表示上一次詢問的兩個答案的和,這次詢問中的讀入的表示點對的兩個數都要\(xor \ (lastans∗op)\),其中\(op\in \\),具體見資料範圍
後話:然而畢竟是蒟蒻種的樹,毒瘤的祝福並沒有使這題送溫暖的本質發生變化qwq
第一行三個整數\(n,m,op\)
接下來一行\(n\)個整數表示每個節點的權值\(val_i\)
再接下來\(n−1\)行每行兩個整數\(x,y\)表示樹上的一條邊
再接下來\(m\)組詢問,每組詢問第一行乙個整數\(num\)表示點對的數量,接下來\(num\)行每行兩個整數\((x,y)\)表示一組點對
對於每組詢問,輸出一行兩個整數分別表示不同權值的數量以及權值的\(mex\)
5 5 0
2 0 0 1 3
1 22 3
2 44 5
1 4 5
3 1 5 5 2 4 4
2 2 4 2 4
4 2 5 3 1 4 3 2 5
1 2 5
2 0
4 42 2
4 43 2
一些你可能根本不需要用到的說明:乙個數集\(s\)的\(mex\)為最小的滿足\(x\notin s\)的非負整數\(x\)
\(subtask1(20\%)\):\(n,m≤1000,\sum num≤1000,op=0\)
\(subtask2(30\%)\):\(n,m≤10^5,\sum num≤10^5\),樹是一條鏈,\(op=0\)
\(subtask3(50\%)\):\(n,m≤10^5,\sum num≤10^5,0≤val_i≤30000\)
完 全 沒 有 感 受 到 溫 暖,雖 然 確 實 是 最 簡 單 的 一 道,剩 下 兩 道 我 改 不 出 來
30000這個數我們很容易除上個64哎
然後隨便用樹剖倍增之類的維護一下,發現單次操作複雜度達到了驚人的\(\log n\frac\),顯然沒救了。
這時候就是分塊出場的時候辣
因為詢問的是鏈的資訊,所以我們考慮對樹的深度進行分塊,既對樹提取一定的關鍵點,相鄰的關鍵點深度差不超過\(\sqrt n\)就可以了,這樣我們就有了\(\sqrt n\)個關鍵點。
然後我們拿關鍵點拼嗎?複雜度達到了更驚人的\(\sqrt n \frac\)
所以考慮先預處理在同一條到跟路徑上關鍵點的路徑資訊,這裡採用手寫\(bitset\)的方法就可以做到\(o(1)\)整數與上\(bitset\)了,然後每個關鍵點向上與順便更新一下就行了。
查詢的時候,不完整的暴力跳,完整的做一次bitset之間的與運算就行了。
複雜度:\(o(n\sqrt n+q(\sqrt n+\frac))\)
code:
#include #include #include #include #define ull unsigned long long
const int n=1e5+10,b=470;
const ull full=~0ull,cut=(1ull<<16)-1;
int ct[cut+1],n,m,op;
int cal(ull x)
using std::max;
struct bitset
bitset()
void friend operator |=(bitset &a,int x)
void friend operator |=(bitset &a,bitset b)
int count()
int mex()
return 233;
}}path[320][320],ans;
int head[n],to[n<<1],next[n<<1],cnt;
void add(int u,int v)
int f[n][19],dep[n],mxdep[n],id[n],rt[n],val[n],pre[n],h;
void dfs(int now)
if(mxdep[now]==h||now==1)
}int lca(int x,int y)
void query(int x,int y)
int s=x;
while(dep[pre[x]]>dep[y]) x=pre[x];
ans|=path[id[s]][id[x]];
while(dep[f[x][0]]>=dep[y]) x=f[x][0],ans|=val[x];
}void query(int x,int y)
int main()
{ scanf("%d%d%d",&n,&m,&op);
for(int i=1;i<=cut;i++) ct[i]=ct[i>>1]+(i&1);
h=sqrt(n)+1;
for(int i=1;i<=n;i++) scanf("%d",val+i);
for(int u,v,i=1;i2019.1.6
洛谷P1250 種樹 解題報告
一條街的一邊有幾座房子。因為環保原因居民想要在路邊種些樹。路邊的地區被分割成塊,並被編號成1 n。每個部分為乙個單位尺寸大小並最多可種一棵樹。每個居民想在門前種些樹並指定了三個號碼b,e,t。這三個數表示該居民想在b和e之間最少種t棵樹。當然,b e,居民必須記住在指定區不能種多於區域地塊數的樹,所...
國家集訓隊2011 種樹 解題報告
題目 a城市有乙個巨大的圓形廣場,為了綠化環境和淨化空氣,市 決定沿圓形廣場外圈種一圈樹。園林部門得到指令後,初步規劃出n個種樹的位置,順時針編號1到n。並且每個位置都有乙個美觀度ai,如果在這裡種樹就可以得到這ai的美觀度。但由於a城市土壤肥力欠佳,兩棵樹決不能種在相鄰的位置 i號位置和i 1號位...
Block Voting 解題報告
這道題做的有點狼狽,效率不高,差一點就tle的ac了。看status裡的,ac的時間大多數都是0ms的。肯定有乙個更有效率的演算法的。下面說下我的狼狽演算法。出處 http acm.jlu.edu.cn joj showproblem.php?pid 1223 問題描述 求每個party的權值。第i...