Problem A 種樹 解題報告

2022-04-29 23:09:08 字數 2880 閱讀 4132

很久很久以前,乙個蒟蒻種了一棵會提問的樹,樹有\(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...