T1:
1 ≤ N ≤ 100000, 1 ≤ M ≤ 2N
題解:
轉化條件:一個圖的每個連通塊爲鏈,等價於每個點的度數小於等於 2 且無環. 轉化後的條件明顯更有利於解決問題。
容易想到當一個點的度數==3時必然是刪它或周圍的點,>3時就是必刪點,成環那麼刪去環上的某個點,我在考試的時候採用了將這些點打上idx的標記,那麼要刪的點就是集齊了所有idx的點(Hash實現),但是環沒辦法快速處理。
這啓示我們當分類討論將選擇範圍縮小爲常數級別時就可以嘗試枚舉了。
Code:
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int n,m;
bool flg_deg3;
vector<int>G[maxn];
vector<pair<int,int> >E;
struct Graph{
int F[maxn],siz[maxn],cir,cirlen,node_deg3,deg[maxn],del;
Graph(){fill(siz+1,siz+maxn,1);}
int find(int x){return !F[x]?x:F[x]=find(F[x]);}
bool merge(int x,int y){
if((x=find(x))==(y=find(y))) return 0;
if(siz[x]<siz[y]) swap(x,y);
F[y]=x,siz[x]+=siz[y];
return 1;
}
void insert(int x,int y){
if(x==del||y==del) return;
if(++deg[x]==3) node_deg3=x;
if(++deg[y]==3) node_deg3=y;
if(!merge(x,y)) cir++,cirlen=siz[find(x)];
}
bool valid(){return !node_deg3&&!cir;}
}f,g[4];
int main()
{
freopen("chain.in","r",stdin);
freopen("chain.out","w",stdout);
read(n),read(m);
int x,y; char op;
while(m--){
while(!isalpha(op=getc()));
if(op=='Q'){
if(flg_deg3){
int s=0;
for(int i=0;i<4;i++) s+=g[i].valid();
printf("%d\n",s);
}
else x=f.cir,printf("%d\n",!x?n:x==1?f.cirlen:0);
}
else{
read(x),read(y);
if(flg_deg3) for(int i=0;i<4;i++) g[i].insert(x,y);
else{
G[x].push_back(y),G[y].push_back(x);
E.push_back(make_pair(x,y));
f.insert(x,y);
if(x=f.node_deg3){
flg_deg3=1,g[3].del=x;
for(int i=0;i<3;i++) g[i].del=G[x][i];
for(int i=0;i<4;i++)
for(int j=0,lim=E.size();j<lim;j++)
g[i].insert(E[j].first,E[j].second);
}
}
}
}
}
T2:
題解:
我的做法:
顯然子樹中的代價與的最近點有關,那麼設表示的最近點在子樹外,且距離爲時子樹中的最小代價;表示的最近點在子樹內,且距離爲時子樹中的最小代價。記錄表示子樹內的點都在子樹內解決的最小代價,最後答案就是。轉移時要枚舉的最近點在哪個子樹,總複雜度。
STD:
Code1:
#include<bits/stdc++.h>
#define maxn 205
#define rep(i,v) for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff)
using namespace std;
int n,K,D[maxn],mxd[maxn],f[maxn][maxn],g[maxn][maxn],G[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
void dfs(int u,int ff){
rep(i,v) dfs(v,u),mxd[u]=max(mxd[u],mxd[v]+1);
for(int i=1;i<n;i++){
f[u][i]=D[i];
rep(j,v) f[u][i]+=min(G[v],f[v][i+1]);
}
g[u][0]=K;
rep(i,v) g[u][0]+=min(G[v],f[v][1]);
for(int i=1;i<=mxd[u];i++){
rep(j,x){
int ret=g[x][i-1]+D[i];
rep(k,v) if(v!=x) ret+=min(G[v],f[v][i+1]);
g[u][i]=min(g[u][i],ret);
}
}
for(int i=0;i<=mxd[u];i++) G[u]=min(G[u],g[u][i]);
}
int main()
{
freopen("logistics.in","r",stdin);
freopen("logistics.out","w",stdout);
memset(f,0x3f,sizeof f),memset(g,0x3f,sizeof g),memset(G,0x3f,sizeof G);
scanf("%d%d",&n,&K);
for(int i=1;i<n;i++) scanf("%d",&D[i]);
for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
dfs(1,0);
printf("%d\n",G[1]);
}
Code2:
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
enum {MAXN = 2010,MAXE = MAXN * 2,INF = 1000000000};
int cost[MAXN],dist[MAXN][MAXN],dp[MAXN][MAXN];
int map[MAXN],end[MAXE],nxt[MAXE];
int tot = 0;
void add(int u,int v)
{
end[tot] = v;
nxt[tot] = map[u];
map[u] = tot++;
}
void dfs_dist(int u,int fath,int *dist)
{
if (fath) dist[u] = dist[fath] + 1;
else dist[u] = 0;
for(int p = map[u];p != -1;p = nxt[p])
if (end[p] != fath) dfs_dist(end[p],u,dist);
}
int N,K;
void dfs(int u,int fath)
{
for(int r = 1;r <= N;r++) dp[u][r] = cost[dist[u][r]];
for(int p = map[u];p != -1;p = nxt[p])
if (end[p] != fath)
{
const int &v = end[p];
dfs(v,u);
for(int r = 1;r <= N;r++)
{
int minv = dp[v][r];
for(int r2 = 1;r2 <= N;r2++)
if (dp[v][r2] + K < minv)
{
minv = dp[v][r2] + K;
}
dp[u][r] += minv;
}
}
}
int main()
{
freopen("logistics.in","r",stdin);
freopen("logistics.out","w",stdout);
int n,k;
scanf("%d%d",&n,&k);
cost[0] = 0;
for(int i = 1;i < n;i++) scanf("%d",&cost[i]);
memset(map,-1,sizeof(map));
int u,v;
for(int i = 0;i < n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
for(int i = 1;i <= n;i++) dfs_dist(i,0,dist[i]);
N = n,K = k;
dfs(1,0);
int minans = INF,minr = 0;
for(int r = 1;r <= N;r++)
if (dp[1][r] < minans)
{
minans = dp[1][r];
minr = r;
}
minans += k;
printf("%d\n",minans);
return 0;
}
T3:
題意:
個點的樹,每個點有顏色,次操作,修改一個點的顏色或查詢到路徑上的第種顏色的個數。
題解:
給每個顏色開個線段樹。
動態開點線段樹+樹剖 。
可以不用樹剖,因爲是數個數有可減性,變成兩條到根的鏈去掉LCA到根的兩倍。到根的路徑就可以子樹修改單點查詢了,
Code:
#include<bits/stdc++.h>
#define maxn 300005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int n,m,Q,a[maxn],rt[maxn],lc[maxn*20],rc[maxn*20],s[maxn*20],sz,ans;
int fa[maxn],dep[maxn],son[maxn],siz[maxn],top[maxn],dfn[maxn],tim;
map<int,int>id;
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
inline int turn(int x){int &y=id[x]; if(!y) y=++m; return y;}
void dfs1(int u,int ff){
dep[u]=dep[fa[u]=ff]+1,siz[u]=1;
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff){
dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp,dfn[u]=++tim;
if(son[u]) dfs2(son[u],tp);
for(int i=fir[u],v;i;i=nxt[i]) if(!dfn[v=to[i]]) dfs2(v,v);
}
void insert(int &i,int l,int r,int x,int d){
if(!i) i=++sz;
s[i]+=d;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) insert(lc[i],l,mid,x,d);
else insert(rc[i],mid+1,r,x,d);
}
int query(int i,int l,int r,int x,int y){
if(!i||!s[i]) return 0;
if(x<=l&&r<=y) return s[i];
int mid=(l+r)>>1,ret=0;
if(x<=mid) ret+=query(lc[i],l,mid,x,y);
if(y>mid) ret+=query(rc[i],mid+1,r,x,y);
return ret;
}
void solve(int u,int v,int t){
ans=0;
for(;top[u]!=top[v];u=fa[top[u]]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans+=query(rt[t],1,n,dfn[top[u]],dfn[u]);
}
if(dep[u]<dep[v]) swap(u,v);
ans+=query(rt[t],1,n,dfn[v],dfn[u]);
printf("%d\n",ans);
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
int x,y,t; char op;
read(n),read(Q);
for(int i=1;i<=n;i++) read(a[i]),a[i]=turn(a[i]);
for(int i=1;i<n;i++) read(x),read(y),line(x,y),line(y,x);
dfs1(1,0),dfs2(1,1);
for(int i=1;i<=n;i++) insert(rt[a[i]],1,n,dfn[i],1);
while(Q--){
while(!isalpha(op=getc()));
if(op=='C'){
read(x),read(t),x^=ans,t=turn(t^ans);
insert(rt[a[x]],1,n,dfn[x],-1),insert(rt[a[x]=t],1,n,dfn[x],1);
}
else{
read(x),read(y),read(t),x^=ans,y^=ans,t=turn(t^ans);
solve(x,y,t);
}
}
}