cf1017g
給定一棵樹,每次操作乙個點,如果這個點是白色就把他染黑,否則遞迴操作所有兒子。或者把乙個子樹染白。或者詢問某個點的顏色(黑白)。
把操作以 o(n
)o(\sqrt n)
o(n
) 劃分成若干段,把每段涉及到的點建一棵類似虛樹的東西,邊權是兩點之間的白點個數。修改操作在這棵樹上改,複雜度 \sqrt n,每段處理完後 o(n) 修改到原樹上。
還有一種巧妙的做法。總體想法是我們想要對修改點打標記。問題是如何設計乙個標記,使得乙個點是黑點當且僅當滿足某個條件。發現如果一開始給每個點打上-1的標記,操作乙個點就把這個點+1,那麼乙個點是黑色當且僅當從他開始向根走的某條路徑和大於0。因此我們樹剖一下維護最大字尾和即可。注意子樹染白操作,不能簡單地打上-1標記,要注意修改子樹根的權值使得它滿足我們的規定。
cf925e
⼀棵 n 個點的有根黑白樹,⼀個陣列 a 和 m 次操作,每次將某個點反色。若⼀個節點 x 為黑色且其子樹內白色節點數量大於 ax,則該節點是「不高興」的。每次操作後輸出「不高興」的節點數目。
同樣對修改分塊,相鄰的 b 個詢問點建立一棵虛樹,容易發現在當前塊內,虛樹上一條邊 (u,v) 在原樹中的點是一起被 u 的子樹影響的,因此可以一起修改貢獻。注意-1(int)>1(unsigned int)
,比較時要注意型別轉換。
#include#define ll long long
#define pb push_back
#define fir first
#define sec second
#define ld long double
using namespace std;
const int n=100010;
typedef pair p;
struct edge ed[n<<1];
int head[n],sz,qy[n],b[n],d[n],t[n],a[n],b[n],tim,st[n],cnt,fa[n],faa[n],f[n][18],deep[n],vis[n],tmp[n],ans=0,pq[n],lev[n];
vector c[n];
void add_edge(int from,int to)
int read()
bool cmp(int a,int b)
void dfs0(int u,int ff)
b[u]=++tim;
}int dfs1(int u,int ff)
t[u]-=sum;
return sum;
}void solve()
sort(b+1,b+cnt+1,cmp);
for(int i=1;ib[st[top]])) top--;
faa[b[i]]=st[top];
st[++top]=b[i]; }
for(int i=1;i<=cnt;i++)
sort(tmp+1,tmp+tot+1);
c[u].clear();
pq[u]=-1;
for(int j=1,p;j<=tot;j=p)
}for(int i=1;i<=m;i++)
cout<0) d[qy[i]]++;
else d[-qy[i]]--;
} dfs1(1,0);
for(int i=1;i<=cnt;i++) }
int main()
for(int i=1;i<=n;i++) t[i]=read();
dfs0(1,0);
for(int j=1;j<=17;j++)
for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=m;i++)
return 0;
}/*by dt_kang*/
暴力分塊矩陣乘法
樸素的演算法 o 4096 64 4096 o 1e9 不用想是超時的。因為每次矩陣乘法中存在很多重複的計算。考慮將矩陣進行分塊優化。預處理出每塊的值。怎麼分塊。考慮對a矩陣的列分塊,和b矩陣的行分塊。因為p是公共的邊,且p 64 需要注意到的是 b矩陣中的取值僅有01那麼如果對b矩陣進行分塊的話。...
優雅的暴力 分塊
關於什麼是分塊,顧名思義,就是將區間分成一塊一塊的,這就是分塊,這是一種優雅的暴力。我們可以將整個區間按照特定的性質分為 sqrt n 個長度為 sqrt n 的塊,來代表整個區間。我們將其稱為一種資料結構,我感覺是因為它維護了一些東西。它遵從乙個思想 小段樸素,大段維護 小段樸素,大段維護 怎麼理...
幾何 組合數學 分治FFT 分塊
題目大意 有n個正四面體,第k個邊長是k個木棍。想要摧毀第k個正四面體,當且進當移除了至少k個正四面體,以及四個結點至少是兩條邊的段點。現在要摧毀至少m個正四面體,問方案數,不考慮順序和空間同構,n 60000,p 105 3 n le60000,p 10 5 3 n 6000 0,p 105 3。...