給你一個不超過 \(10^9\) 的數字 \(n\) 和一個交換次數上限 \(k\),node
每次操做對這個 數字 \(n\) 的其中兩位進行交換,ios
好比 201 能夠換成 102,git
讓你進行 \(k\) 次操做,求出交換後最大的數字和最小的數字的差的絕對值。網絡
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <string.h> using namespace std; #define int long long const int manx=1e6+10; const int mamx = 1e6 + 11; const int mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int t,n,m,now[manx],cnt,maxn,minx,k; int a[manx],b[manx],js,bz; void dfs_min(int k,int cnt){ if(k <= 0 || cnt >= js){ int s = 0; for(int i = 1;i <= js;i++) s = s*10 + b[i]; if(s > bz) minx = min(s,minx);//s-->minx,100 --> 0 /* bz : 標準 含義是當前這個序列組成的數必須比 10^(js-1)大,(防止前導零) */ return; } for(int i = cnt + 1;i <= js; i++){ if(b[i] <= b[cnt]){ swap(b[i],b[cnt]); dfs_min(k-1,cnt+1); swap(b[i],b[cnt]);//回溯 } } dfs_min(k,cnt+1);//當前這個數即爲最小數,直接搜索下一位 } void dfs_max(int k,int cnt){ if(k <= 0 || cnt >= js){ int s = 0; for(int i = 1;i <= js;i++) s = s*10 + a[i]; maxn = max(maxn,s); return; } for(int i = cnt + 1;i <= js; i++){ if(a[i] >= a[cnt]){ swap(a[i],a[cnt]); dfs_max(k-1,cnt+1); swap(a[i],a[cnt]); } } dfs_max(k,cnt+1);//原理同上 } void solve(){ memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(now,0,sizeof(now)); cnt = js = 0; minx = inf, maxn = 0; n = read();k = read(); while(n){ now[++cnt] = n%10; //倒序去位數 n = n/10; } bz = 1; for(int i = cnt;i >= 1; i--){ a[++js] = now[i],b[js] = now[i];//不能夠連等嗎 bz *= 10; } bz = bz/10;//位數是(js-1) dfs_max(k,1),dfs_min(k,1); cout<< maxn - minx << '\n'; } signed main(){ t = read(); while(t--) solve(); return 0; }
咱們把從 \(u\) 到 \(u+k\) 做爲一組,叫作操做oop
那麼第 \(i\) 次和第 \(i+1\) 次操做同時進行的話,那麼獲得翻轉的數只有 \(i\) 和 \(i+k\)優化
所以同時翻轉任意距離 \(k\) 的操做就等價於「翻轉任意連續 K 盞燈的狀態」ui
等價的緣由spa
「翻轉任意連續 K 盞燈的狀態」 是由一次 \(<a>\), 和若干個 \(<b>\) 操做組成code
而且 \(<b>\) 操做還分紅了固定的幾組,所以能夠全面的操做到每一位ci
每一次 \(<b>\) 操做都訂價與翻轉一組相鄰 \(k\) 的兩盞燈,且組與組之間沒有影響
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const int manx=1e6+10; const int mamx = 1e6 + 11; const ll mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int T ,a[manx] ,n ,k ,ans; bool pd[manx]; inline int Check(int n ,int k ,bool pd[] ,int a[]){ int ret = 0; for(int i = 1;i <= k;i ++){ int cnt = 0,minx = inf; for(int j = i; j <= n; j+=k){ ret += a[j]; minx = min(minx ,a[j]); if(pd[j] == 0) cnt++;//記錄零的個數 } if(cnt % 2 != 0) ret -= minx; } return ret; } int main(){ T = read(); while(T--){ ans = 0; n = read(); k = read(); for(int i = 1;i <= n; i++) pd[i] = read(); for(int i = 1;i <= n; i++) a[i] = read(); if(k == 1){ for(int i =1;i <= n; i++) ans += a[i]; }else{ ans = Check(n ,k ,pd ,a); /* 兩種狀況,第一個是不翻轉1-k,獲得的最小值, 第二個是翻轉後獲得的最小值, (由於就兩種狀況前 1-k 翻與不翻) */ for(int i = 1;i <= k; i++) pd[i] ^= 1;//pd [i] ---> pd [k] 100 --> 0 ans = max(ans,Check(n ,k ,pd ,a)); } cout<<ans<<'\n'; } return 0; }
顯然能夠用樹鏈剖分進行操做,和線段樹進行維護,
路徑修改,求子樹間兩點路徑的總和(不是子樹查詢)
值得注意的是,點權變邊權,操做路徑修改是要注意 \(dfn[u]\) 的位置,避免多加,或少加
不妨設點 \(x\) 與它的父親 \(fa[x]\) 相連的邊的權值爲 \(p[x]\),
考慮 \(p[x]\) 會對那些點對產生貢獻?
顯然是通過 \(x——fa[x]\) 這條邊的那些點對。記 \(size_[x]\) 爲以 \(x\) 爲根的子樹的大小。
則通過 \(x——fa[x]\) 的點對有 \(size_[x]×(size_[i] – size_[x])\) 對
因而,子樹 \(i\) 內的點 \(x\) 的貢獻
#include <iostream> #include <cstdio> #include <cstring> #include <string.h> #include <queue> #include <algorithm> using namespace std; #define ll long long const int manx = 1e6; const int mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read(){ char c = getchar(); int x = 0, f = 1; for( ;!isdigit(c);c = getchar()) if(c == '-') f = -1; for( ;isdigit(c);c = getchar()) x = x*10 + (c^48); return x * f; } struct node{ int v,nxt; }e[manx]; int head[manx],cnt,n,m,dep[manx],fa[manx],size_[manx],val[manx],pre[manx],tp[manx],dfn[manx],hson[manx]; int js,sigma1,sigma2; inline void add(int u,int v){ e[++cnt].nxt = head[u]; e[cnt].v = v; head[u] = cnt; } namespace Tree{ #define ls i<<1 #define rs i<<1|1 struct tree{ int l;int r; ll sum,lazy; }tr[manx<<3]; inline void up(int i){ tr[i].sum = tr[ls].sum + tr[rs].sum ; } inline void down(int i){ if(tr[i].lazy){ ll x = tr[i].lazy ; tr[ls].sum += (tr[ls].r - tr[ls].l +1)*x; tr[rs].sum += (tr[rs].r - tr[rs].l +1)*x; tr[ls].lazy += x; tr[rs].lazy += x; tr[i].lazy = 0; } } inline void build(int i,int l,int r){ tr[i].l = l;tr[i].r = r; if(l == r){ tr[i].sum = val[pre[l]]; return ; } int mid = (l + r)>>1; build(ls,l,mid); build(rs,mid+1,r); up(i); } inline void add(int i,int l,int r,int w){ if(tr[i].l >= l && tr[i].r <= r){ tr[i].sum += (tr[i].r - tr[i].l +1)*w; tr[i].lazy += w; return; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= r)add(ls,l,r,w); else if(mid < l)add(rs,l,r,w); else add(ls,l,mid,w),add(rs,mid+1,r,w); up(i); } inline ll only_query(int i,int u){ if(tr[i].l == tr[i].r ){ return tr[i].sum ; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= u) return only_query(ls,u); else if(mid < u) return only_query(rs,u); } inline ll query(int i,int l,int r){ if(tr[i].l >= l && tr[i].r <= r){ return tr[i].sum ; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= r)return query(ls,l,r); else if(mid < l)return query(rs,l,r); return query(ls,l,mid)+query(rs,mid+1,r); } } namespace Node{ inline void dfs1(int u,int pre,int d){ fa[u] = pre; dep[u] = d;size_[u] = 1; for(int i = head[u]; i;i = e[i].nxt){ int v = e[i].v ; if(v != pre){ dfs1(v,u,d+1); size_[u] += size_[v]; if(!hson[u] || size_[hson[u]] < size_[v]){ hson[u] = v; } } } } inline void dfs2(int u,int top){ tp[u] = top; dfn[u] = ++js; pre[js] = u; if(!hson[u])return; dfs2(hson[u],top); for(int i = head[u];i;i = e[i].nxt ){ int v = e[i].v ; if(v != fa[u] && v != hson[u]){ dfs2(v,v); } } } inline void add(int u,int v,int w){ while(tp[u] != tp[v]){ if(dep[tp[u]] < dep[tp[v]])swap(u,v); Tree::add(1,dfn[tp[u]],dfn[u],w); u = fa[tp[u]]; } if(dep[u]>dep[v])swap(u,v); Tree::add(1,dfn[u] + 1,dfn[v],w); } inline void query(int u){ for(int i = head[u]; i; i = e[i].nxt ){ int v = e[i].v ; if(v != fa[u]){ Node::query(v); int s = Tree::only_query(1,dfn[v]); // cout<<s<<" "<<v<<endl; sigma1 += (s * size_[v]); sigma2 += (s * size_[v] * size_[v]); } } return; } } char a[9]; int main(){ //freopen("pp.in","r",stdin); //freopen("network.out","w",stdout); n = read();m = read(); for(int i = 1;i < n; i++){ int x = read(), y = read(); val[i+1] = y; add(i+1,x); add(x,i+1); } Node::dfs1(1,0,1),Node::dfs2(1,1),Tree::build(1,1,n); for(int i = 1;i <= m; i++){ cin>>a; ll ans = 0; ll fan = 0; int x,y,z; if(a[0] == 'I'){ x = read(); y = read(); z = read(); Node::add(x,y,z); }else{ x = read(); sigma1 = 0; sigma2 = 0; Node::query(x); cout<<size_[x] * sigma1 - sigma2 <<endl; } } return 0; }
感謝觀看