10月——备战区域赛
1 HDU4812(树分治
题目:求一颗树上的一条路径,其上所有点的值之积为k。
思路:裸的树分治,写的时候感觉肯定能迅速过掉,,,,结果做了大半天。。。越来越觉得自己出数据的能力是极为重要的!!!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=1e5+3000; const ll mod=1e6+3; int n,k; int val[maxn]; vector<int> G[maxn]; int cnt; bool usd[maxn]; int inv[mod]; int qpow(ll a,ll p){ ll ans=1; while(p){ if(p&1) ans=(ans*a)%mod; p>>=1; a=(a*a)%mod; } return ans; } void count(int v,int f=-1){ cnt++; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(usd[u]||u==f) continue; count(u,v); } } int center,mind; int snum[maxn]; void getCenter(int v,int f=-1){ int maxs=0; snum[v]=0; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(usd[u]||u==f) continue; getCenter(u,v); maxs=max(maxs,snum[u]+1); snum[v]+=snum[u]+1; } int val=max(cnt-snum[v]-1,maxs); if(val<mind){ mind=val; center=v; } } int tab[mod],chd[mod],ch; int tmptab[mod],chtmp[mod],tch; P ans; void cal_tab(int v,ll mul=1,int f=-1){ ll m=mul*val[v]%mod; if(!tmptab[m]){ chtmp[tch++]=m; tmptab[m]=v; }else{ if(tmptab[m]>v) tmptab[m]=v; } for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f||usd[u]) continue; cal_tab(u,m,v); } } void solve(int v){ usd[v]=1; ll dv=inv[val[v]]; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(usd[u]) continue; cal_tab(u); for(int j=0;j<tch;j++){ int tv=chtmp[j]; int tar=inv[tv]*dv%mod*k%mod; if((ll)val[v]*tv%mod==k){ int a=v,b=tmptab[tv]; if(a>b) swap(a,b); ans=min(ans,P(a,b)); } if(tab[tar]){ int a=tab[tar],b=tmptab[tv]; if(a>b) swap(a,b); ans=min(ans,P(a,b)); } } for(int j=0;j<tch;j++){ int tv=chtmp[j]; if(tab[tv]){if(tmptab[tv]<tab[tv]) tab[tv]=tmptab[tv];} else{ tab[tv]=tmptab[tv]; chd[ch++]=tv; } tmptab[tv]=0; } tch=0; } for(int i=0;i<ch;i++){ tab[chd[i]]=0; } ch=0; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(usd[u]) continue; mind=1e9; cnt=0; count(u); getCenter(u); solve(center); } } void pre_cal(){ for(int i=0;i<mod;i++){ inv[i]=qpow(i,mod-2); } } void init(){ for(int i=0;i<=n;i++){ G[i].clear(); } ans=P(INF,INF); memset(usd,0,sizeof usd); } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); pre_cal(); while(cin>>n>>k){ init(); for(int i=1;i<=n;i++){ scanf("%d",&val[i]); } for(int i=0;i<n-1;i++){ int x,y; scanf("%d%d",&x,&y); G[x].pb(y); G[y].pb(x); } mind=1e9,cnt=0; count(1);getCenter(1); solve(center); if(ans==P(INF,INF)){ puts("No solution"); }else{ printf("%d %d\n",(int)ans.fs,(int)ans.se); } } return 0; }
2 CodeForces. 149D
题目:给出一个括号序列,匹配的括号中有一个染色,并且相邻的括号颜色不能相同,问染色方法种数。
思路:区间dp,但是这题的分类讨论有点蛋疼。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int mod=1e9+7; const int maxlen=1000; const int maxn=1000; char s[maxn]; int mat[maxn]; int stk[maxn],top=0; ll dp[maxlen][maxlen][3][3]; inline void ma(ll &a,ll b){a=(a+b)%mod;} int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); scanf("%s",s); int len=strlen(s); for(int i=0;i<len;i++){ if(top==0){ stk[top++]=i; }else{ if(s[i]==')'){ mat[i]=stk[top-1]; mat[stk[top-1]]=i; top--; }else{ stk[top++]=i; } } } for(int k=2;k<=len;k+=2){ for(int i=0;i<len;i++){ int j=i+k-1; if(j>=len) break; if(mat[i]==j){ if(k==2){ dp[i][j][1][0]=1; dp[i][j][0][1]=1; dp[i][j][0][2]=1; dp[i][j][2][0]=1; }else{ for(int a1=0;a1<3;a1++){ for(int b1=0;b1<3;b1++){ if(a1>0&&b1>0||a1==0&&b1==0) continue; for(int a2=0;a2<3;a2++){ for(int b2=0;b2<3;b2++){ if((a1==0||a1!=a2)&&(b1!=b2||b1==0)){ ma(dp[i][j][a1][b1],dp[i+1][j-1][a2][b2]); } } } } } } }else{ int m=mat[i]; for(int a1=0;a1<3;a1++){ for(int b1=0;b1<3;b1++){ for(int a2=0;a2<3;a2++){ if(a2==b1&&a2) continue; for(int b2=0;b2<3;b2++){ ma(dp[i][j][a1][b2],dp[i][m][a1][b1]*dp[m+1][j][a2][b2]%mod); } } } } } } } ll ans=0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ ma(ans,dp[0][len-1][i][j]); } } cout<<ans<<endl; return 0; }
3 poj3280(区间dp
题目:求把一个字符串通过增删字符变为回文串的最小花费。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=3000; int n,m; char s[maxn]; int cost[300][2]; int dp[maxn][maxn]; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); memset(cost,-1,sizeof cost); memset(dp,0x3f,sizeof dp); cin>>n>>m; scanf("%s",s); for(int i=1;i<=n;i++){ char c; int a,b; cin>>c; scanf("%d %d",&a,&b); cost[c][0]=a; cost[c][1]=b; } for(int i=0;i<m;i++) dp[i][i]=0; for(int i=0;i<m-1;i++) if(s[i]==s[i+1]) dp[i][i+1]=0; for(int k=2;k<=m;k++){ for(int i=0;i<m;i++){ int j=i+k-1; if(j>=m) break; if(s[i]==s[j]){ dp[i][j]=min(dp[i][j],dp[i+1][j-1]); } if(cost[s[i]][1]!=-1){ dp[i][j]=min(dp[i][j],dp[i+1][j]+cost[s[i]][1]); dp[i][j]=min(dp[i][j],dp[i+1][j]+cost[s[i]][0]); } if(cost[s[j]][1]!=-1){ dp[i][j]=min(dp[i][j],dp[i][j-1]+cost[s[j]][1]); dp[i][j]=min(dp[i][j],dp[i][j-1]+cost[s[j]][0]); } } } cout<<dp[0][m-1]<<endl; return 0; }
4 HDU 2476(区间dp
题目:给两个字符串,每次操作可以把a串的一段区间全部变成同一个字符,问把a变成b的最少次数。
思路:dp[i][j]表示把i到j的空串变成b的花费,然后据此更新ans,但是明显感觉理解得不到位........有机会再看看这题.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxlen=200; char a[maxlen],b[maxlen]; int dp[maxlen][maxlen]; int ans[maxlen]; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(scanf("%s%s",a,b)!=EOF){ int len = strlen(a); for(int i=0;i<len;i++) dp[i][i]=1; for(int j=0;j<len;j++){ for(int i=j-1;i>=0;i--){ dp[i][j]=dp[i+1][j]+1; for(int k=i+1;k<=j;k++) if(b[k]==b[i]) dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]); } } ans[0]=(b[0]==a[0]?0:1); for(int i=1;i<len;i++){ ans[i]=ans[i-1]; if(b[i]!=a[i]) ans[i]++; ans[i]=min(ans[i],dp[0][i]); for(int j=0;j<i;j++) ans[i]=min(ans[i],ans[j]+dp[j+1][i]); } printf("%d\n",ans[len-1]); } return 0; }
5 LightOJ 1268 (KMP矩阵快速幂
题目:给出一个字典和一个禁止串,求能组成的长度为n的字符串的种数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ #include <bits/stdc++.h> #define pb push_back #define se second #define fs first #define sq(x) (x)*(x) #define eps (5e-12) #define LB lower_bound #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define bk back() #define PB pop_back #define clr(x) memset((x),0,sizeof (x)); using namespace std; typedef long long ll; typedef unsigned int ui; typedef pair<ll,ll> P; const int maxn=60; void kmp_pre(char x[],int m,int next[]){ int i,j; j=next[0]=-1; i=0; while(i<m){ while(-1!=j && x[i]!=x[j])j=next[j]; next[++i]=++j; } } ui tmp[maxn][maxn]; int len; struct Matrix{ ui a[maxn][maxn]; void mul(const Matrix &m){ memcpy(tmp,a,sizeof a); clr(a); for(int i=0;i<len;i++){ for(int j=0;j<len;j++){ for(int k=0;k<len;k++){ a[i][j]+=tmp[i][k]*m.a[k][j]; } } } } Matrix(){memset(a,0,sizeof a);} }; Matrix qpow(Matrix a,int p){ Matrix ans,tmp; for(int i=0;i<len;i++) ans.a[i][i]=1; while(p){ if(p&1) ans.mul(a); p>>=1; tmp=a; a.mul(tmp); } return ans; } int next[maxn]; int T; int n; char dir[maxn],s[maxn]; int mat[maxn][maxn]; int cas=0; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>T; while(T--){ cin>>n; scanf("%s%s",dir,s); len=strlen(s); int sz=strlen(dir); kmp_pre(s,len,next); clr(mat); for(int i=0;i<len;i++){ for(int j=0;j<sz;j++){ int v=i; while(v!=-1&&s[v]!=dir[j]) v=next[v]; mat[v+1][i]++; } } Matrix t; memcpy(t.a,mat,sizeof mat); Matrix ans=qpow(t,n); ui res=0; for(int i=0;i<len;i++) res+=ans.a[i][0]; printf("Case %d: ",++cas); cout<<res<<endl; } return 0; }
6 PKU. 3744(概率dp,矩阵快速幂
题目:一条直线上有若干个地雷,每次只能走一步或两部,求安全通过的概率。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (3e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int lim=2; double tmp[10][10]; struct Matrix{ double a[10][10]; void mul(const Matrix &C){ memcpy(tmp,a,sizeof a); clr(a); for(int i=0;i<lim;i++){ for(int j=0;j<lim;j++){ for(int k=0;k<lim;k++){ a[i][j]+=tmp[i][k]*C.a[k][j]; } } } } Matrix(){clr(a);} }; Matrix qpow(Matrix a,int p){ Matrix ans,tmp; for(int i=0;i<lim;i++) ans.a[i][i]=1; while(p){ if(p&1) ans.mul(a); p>>=1; tmp=a; a.mul(tmp); } return ans; } const int maxn=20; int n; double p; int m[maxn]; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); while(scanf("%d%lf",&n,&p)!=EOF){ for(int i=1;i<=n;i++){ scanf("%d",&m[i]); } sort(m+1,m+n+1); Matrix t; t.a[0][0]=p; t.a[0][1]=1-p; t.a[1][0]=1; t.a[1][1]=0; double ans=1; m[0]=0; for(int i=1;i<=n;i++){ Matrix res; res=qpow(t,m[i]-m[i-1]-1); ans*=res.a[1][0]*(1-p); } printf("%.7f\n",ans); } return 0; }
7 CodeForces383D(dp
题目:给出一个数列,要求取一个连续子序列且使得区间和为0的取法有多少种。
思路:dp[i][j]表示以第i个字符结尾和为j的种数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (3e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=1005,maxm=20005; const int sh=10000; const ll mod=1e9+7; int n; int dp[maxn][maxm]; int a[maxn]; int main(){ //freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=0;i<n;i++){ dp[i+1][a[i+1]+sh]++,dp[i+1][a[i+1]+sh]%mod; dp[i+1][-a[i+1]+sh]++,dp[i+1][-a[i+1]+sh]%mod; for(int j=0;j<maxm;j++){ if(j+a[i+1]<maxm){ dp[i+1][j+a[i+1]]=((ll)(dp[i+1][j+a[i+1]])+dp[i][j])%mod; } if(j-a[i+1]>=0){ dp[i+1][j-a[i+1]]=((ll)(dp[i+1][j-a[i+1]])+dp[i][j])%mod; } } } ll ans=0; for(int i=1;i<=n;i++){ ans=(ans+(ll)dp[i][sh])%mod; } cout<<ans<<endl; return 0; }
8 Poj1276(多重背包
思路:二进制拆分物品后01背包求解,还有一种用单调队列的优化做法复杂度更好,但是还没搞懂。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (3e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=15; const int maxm=1e5+399; int n; int c[maxn],d[maxn]; bool dp[maxm]; int ca; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(scanf("%d%d",&ca,&n)!=EOF){ for(int i=0;i<n;i++) scanf("%d%d",&c[i],&d[i]); clr(dp); dp[0]=1; for(int i=0;i<n;i++){ for(int k=0;;k++){ if((1<<k)>c[i]) break; for(int j=ca-1;j>=0;j--){ if(j+(1<<k)*d[i]>ca) continue; if(dp[j]){ dp[j+(1<<k)*d[i]]=1; } } c[i]-=(1<<k); } if(c[i]>0){ for(int j=ca-1;j>=0;j--){ if(j+c[i]*d[i]>ca) continue; if(dp[j]) dp[j+c[i]*d[i]]=1; } } } int ans=0; for(int i=ca;i>=0;i--){ if(dp[i]){ ans=i; break; } } printf("%d\n",ans); } return 0; }
9 POJ 3267(dp
题目:给出一个字典和一个串,问最少删除多少字符使得串完全由字典中的词组成。
思路:重点是枚举每个词和钱一个词的分割位置,这个需要在计算匹配的时候从后向前做。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (3e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; int w,l; char dir[650][60]; int len[650]; char s[1000]; int dp[400]; int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); memset(dp,0x3f,sizeof dp); cin>>w>>l; scanf("%s",s); for(int i=1;i<=w;i++){ scanf("%s",dir[i]); len[i]=strlen(dir[i]); } dp[0]=0; for(int i=1;i<=l;i++){ dp[i]=dp[i-1]+1; for(int x=0;x<=w;x++){ int p1=i-1,px=len[x]-1; for(;p1>=0;p1--){ if(dir[x][px]==s[p1]){ px--; } if(px<0) break; } if(px<0){ dp[i]=min(dp[i],dp[p1]+i-p1-len[x]); } } } cout<<dp[l]<<endl; return 0; }
思路:先去掉有度数限制的点求最小生成树,然后把得到的若干树和这个点相连。之后枚举加边(增加有限制点的度数),删去出现环上最大的边,做到权和不减为止。
其实基本是个代码题。。。。这么点东西写了两个小时。。。还好1A了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=600; struct EDGE{ int from,to,d; bool in; EDGE(int from,int to,int d):from(from),to(to),d(d),in(0){} EDGE(){} }E[maxn*2]; vector<int> G[maxn]; string es[maxn][2]; int w[maxn]; int n; set<string> S; map<string,int> id; int sz; int p; int maxid; int lim,deg; void addedge(int from,int to,int d){ G[from].pb(sz); E[sz++]=EDGE(from,to,d); G[to].pb(sz); E[sz++]=EDGE(to,from,d); } void read(){ cin>>n; for(int i=0;i<n;i++){ string a,b; cin>>a>>b; int d; scanf("%d",&d); es[i][0]=a;es[i][1]=b; w[i]=d; S.insert(a);S.insert(b); } set<string>::iterator it=S.begin(); maxid=0; for(;it!=S.end();it++){ id[*it]=++maxid; } p=id["Park"]; cin>>lim; for(int i=0;i<n;i++){ int u=id[es[i][0]],v=id[es[i][1]]; addedge(u,v,w[i]); } } int mincost[40],mine[40]; int treeid; int vis[50]; int prim(int v){ treeid++; memset(mincost,0x3f,sizeof mincost); mincost[v]=0,mine[v]=-1; bool f=1; int tol=0; while(f){ f=0; int mc=INF,me,vv; for(int i=1;i<=maxid;i++){ if(mincost[i]<mc&&!vis[i]&&i!=p){ mc=mincost[i]; me=mine[i]; vv=i; f=1; } } if(!f) break; vis[vv]=treeid; for(int i=0;i<G[vv].size();i++){ int id=G[vv][i]; EDGE &e=E[id]; if(mincost[e.to]>e.d){ mincost[e.to]=e.d; mine[e.to]=id; } } E[me].in=E[me^1].in=1,tol+=E[me].d; } return tol; } int maxe1[40],maxid1[40]; void dfs(int v,int f=-1){ for(int i=0;i<G[v].size();i++){ int id=G[v][i]; EDGE &e=E[id]; if(e.to==f||!e.in) continue; if(e.d<maxe1[v]){ maxe1[e.to]=maxe1[v]; maxid1[e.to]=maxid1[v]; } else{ maxe1[e.to]=e.d; maxid1[e.to]=id; } dfs(e.to,v); } } int cost=0; void solve(){ for(int i=1;i<=maxid;i++) if(i!=p&&!vis[i]) cost+=prim(i); memset(mincost,0x3f,sizeof mincost); for(int i=0;i<G[p].size();i++){ int e=G[p][i]; int t=vis[E[e].to]; if(mincost[t]>E[e].d){ mincost[t]=E[e].d; mine[t]=e; } } for(int i=1;i<=treeid;i++){ E[mine[i]].in=E[mine[i]^1].in=1; cost+=E[mine[i]].d; } deg=treeid; while(deg<lim){ memset(maxe1,0,sizeof maxe1); dfs(p); int a=0,b,c; for(int i=0;i<G[p].size();i++){ int id=G[p][i]; EDGE &e=E[id]; if(!e.in){ if(e.d-maxe1[e.to]<a){ a=e.d-maxe1[e.to]; b=id; c=maxid1[e.to]; } } } if(!a) break; deg++; E[b].in=E[b^1].in=1; E[c].in=E[c^1].in=0; cost+=a; } printf("Total miles driven: %d",cost); } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); read(); solve(); return 0; }
11 poj 2763(修改边权+路径长度查询
思路:通过树的dfs序列把路径求长变成区间求和,lca也可以通过dfs序列处理。(其实这题是个裸树剖
ps:这题常数写挫了。。。一直t,以为自己写错了,结果交了好多发之后3900ms过了一次,遂上读入挂。。结果就成了1800ms。。。真是可怕。。。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=2e5+3000; int lim; struct BIT{ int a[maxn]; int sum(int p){ int ans=0; while(p>0){ ans+=a[p]; p-=p&-p; } return ans; } void add(int p,int x){ while(p<lim){ a[p]+=x; p+=p&-p; } } int range(int a,int b){ if(b<a) return 0; return sum(b)-sum(a-1); } }B; struct EDGE{ int from,to,id; }es[maxn]; int w[maxn]; vector<int> G[maxn]; int sz; void addedge(int from,int to,int ww,int id){ es[sz].from=from,es[sz].to=to,es[sz].id=id; G[from].pb(sz++); es[sz].to=from,es[sz].from=to,es[sz].id=id; G[to].pb(sz++); w[id]=ww; } int dfsq[maxn]; int dfsr[maxn]; int rp[maxn][2]; int dfsp,dfsrp=1; int dep[maxn]; int ap[maxn],ape[maxn]; void dfs(int v,int f=-1,int d=0){ dep[v]=d,ap[v]=dfsp,ape[v]=dfsrp,dfsq[dfsp++]=v; for(int i=0;i<G[v].size();i++){ int ei=G[v][i]; EDGE &e=es[ei]; if(e.to==f) continue; rp[e.id][0]=dfsrp,B.add(dfsrp++,w[e.id]); dfs(e.to,v,d+1); dfsq[dfsp++]=v; rp[e.id][1]=dfsrp,B.add(dfsrp++,-w[e.id]); } } int st[20][maxn]; void rmq_init(){ for(int i=0;i<dfsp;i++) st[0][i]=dfsq[i]; for(int k=1;k<20;k++){ for(int i=0;i<dfsp;i++){ int l=i,r=i+(1<<(k-1)); if(r>=dfsp) break; if(dep[st[k-1][l]]<dep[st[k-1][r]]) st[k][l]=st[k-1][l]; else st[k][l]=st[k-1][r]; } } } int lca(int a,int b){ int u=ap[a],v=ap[b]; if(u>v) swap(u,v); v++; int k=0; while(1<<(k+1)<=v-u) k++; int l=u,r=v-(1<<k); if(dep[st[k][l]]<dep[st[k][r]]) return st[k][l]; else return st[k][r]; } int n,q,s; template <class T> inline bool scan_d(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!='-'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); ret*=sgn; return 1; } inline void out(int x) { if(x>9) out(x/10); putchar(x%10+'0'); } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); memset(dep,0x3f,sizeof dep); scan_d(n);scan_d(q);scan_d(s); lim=2*n+3000; for(int i=0;i<n-1;i++){ int a,b,w; scan_d(a);scan_d(b);scan_d(w); addedge(a,b,w,i+1); } dfs(1); rmq_init(); while(q--){ int op; scan_d(op); if(op==0){ int u; scanf("%d",&u); int m=lca(u,s); if(m<1||m>n) return 1; int ans=0; ans=B.sum(ape[u]-1)+B.sum(ape[s]-1)-2*B.sum(ape[m]-1); s=u; out(ans); puts(""); }else{ int a,b; scan_d(a);scan_d(b); int ch=b-w[a]; B.add(rp[a][0],ch); B.add(rp[a][1],-ch); w[a]=b; } } return 0; }
12 CF 343D(线段树
题目:一棵树上有两种操作,把一个节点和所有的祖先节点放空,把一个子树的所有节点灌满水。实时询问某个节点的状态。
思路:先做一次后序遍历,把树转化成序列。然后灌满一棵子树相当于清楚子树上的所有标记。放空相当于单点更新。需要注意的一点是,对于整棵子树的清空时要判断子树上有没有染色点,如果有,需要在子树的父节点上染色,否则可能会因为覆盖了子树上的染色节点导致父节点变成未染色状态。
还有很多人是用set直接做的,这样仍需做后序遍历,然后区间染色相当与往set里插点,区间删除由于已经染色的点是O(q)的,所以可以暴力删。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxnode=2e6+300; struct Node { int l,r; Node *ch[2]; bool fill,emp; void pushdown(){ if(r-l<=1) return; if(fill){ fill=0; ch[0]->fill=ch[1]->fill=1; ch[0]->emp=ch[1]->emp=0; } } }NS[maxnode]; int np; Node *newNode(){ Node *n=&NS[np++]; n->emp=1,n->fill=0; return n; } Node *root; void clear(){ np=0; root=newNode(); } void build(Node *n,int l,int r){ n->l=l,n->r=r; if(r-l<=1) return; n->ch[0]=newNode();n->ch[1]=newNode(); build(n->ch[0],l,(l+r)/2); build(n->ch[1],(r+l)/2,r); } void empty(Node *n,int a){ n->pushdown(); int l=n->l,r=n->r; if(r-l<=1){ n->emp=1; return; } int m=(l+r)/2; if(a>=m) empty(n->ch[1],a); else empty(n->ch[0],a); n->emp=n->ch[0]->emp|n->ch[1]->emp; } void fill(Node *n,int a,int b){ n->pushdown(); int l=n->l,r=n->r; if(l>=b||r<=a) return; if(l>=a&&r<=b){ n->fill=1; n->emp=0; return; } fill(n->ch[0],a,b); fill(n->ch[1],a,b); n->emp=n->ch[0]->emp|n->ch[1]->emp; } bool query(Node *n,int a,int b){ int l=n->l,r=n->r; n->pushdown(); if(l>=b||r<=a) return 0; if(l>=a&&r<=b) return n->emp; return query(n->ch[0],a,b)|query(n->ch[1],a,b); } const int maxn=5e5+300; int n; vector<int> G[maxn]; int dfsn[maxn],dfso[maxn],dfsb[maxn],fa[maxn]; int sz=0; void dfs(int v,int f=-1){ dfso[v]=sz; fa[v]=f; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,v); } dfsb[v]=sz; dfsn[sz++]=v; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); clear(); cin>>n; for(int i=0;i<n-1;i++){ int a,b; scanf("%d%d",&a,&b); G[a].pb(b); G[b].pb(a); } dfs(1); build(root,0,sz); int q; cin>>q; while(q--){ int op,a; scanf("%d%d",&op,&a); if(op==1){ if(query(root,dfso[a],dfsb[a]+1)&&fa[a]!=-1) empty(root,dfsb[fa[a]]); fill(root,dfso[a],dfsb[a]+1); }else if(op==2){ empty(root,dfsb[a]); }else{ printf("%d\n",1^query(root,dfso[a],dfsb[a]+1)); } } return 0; }
13 HDU 4126(dfs,最小生成树
题目:给出一个图,每次改变原图中一条边的权值,询问改变后最小生成树的权和。
思路:有个比较关键的证明,对于一个本来在最小生成树上的边,去掉这个边之后再做最小生成树肯定也包含了得到的两个树。(证明还是没想清楚。。。
然后暴力跑。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-7) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (a)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<int,int> P; const int maxn=3005; struct EDGE{ int from,to,w; EDGE(int from,int to,int w):from(from),to(to),w(w){} bool operator < (const EDGE &C)const{ return w<C.w; } }; vector<EDGE> G[maxn]; vector<EDGE> es; vector<EDGE> T[maxn]; int n,m; int len[maxn][maxn]; int dis[maxn][maxn]; bool on[maxn][maxn]; void init(){ for(int i=0;i<=n;i++){ G[i].clear(); T[i].clear(); } es.clear(); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ dis[i][j]=len[i][j]=INF; on[i][j]=0; } } } int fa[maxn]; int find(int x){ if(fa[x]==x) return x; return fa[x]=find(fa[x]); } bool same(int x,int y){return find(x)==find(y);} int mst(){ int ans=0; for(int i=0;i<n;i++) fa[i]=i; for(int i=0;i<es.size();i++){ EDGE &e=es[i]; if(same(e.from,e.to)) continue; T[e.from].pb(e); T[e.to].pb(EDGE(e.to,e.from,e.w)); fa[find(e.to)]=find(e.from); on[e.to][e.from]=on[e.from][e.to]=1; ans+=e.w; } return ans; } bool vis[maxn]; void lab(int v,int f){ vis[v]=1; for(int i=0;i<T[v].size();i++){ int u=T[v][i].to; if(u==f) continue; lab(u,v); } } int mindis; void dfs(int v,int f){ for(int i=0;i<G[v].size();i++){ EDGE &e=G[v][i]; if(e.w>=mindis) break; if(e.to==f||vis[e.to]) continue; mindis=e.w; break; } for(int i=0;i<T[v].size();i++){ int u=T[v][i].to; if(u==f||!vis[u]) continue; dfs(u,v); } } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(cin>>n>>m,n){ init(); for(int i=0;i<m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); es.pb(EDGE(x,y,z)); G[x].pb(EDGE(x,y,z)); G[y].pb(EDGE(y,x,z)); len[x][y]=len[y][x]=z; } sort(es.begin(),es.end()); for(int i=0;i<n;i++){ sort(G[i].begin(),G[i].end()); } int tol=mst(); int Q; scanf("%d",&Q); double ans=0; for(int qq=0;qq<Q;qq++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); if(!on[x][y]){ ans+=tol; continue; } if(dis[x][y]!=INF){ if(dis[x][y]<z){ ans+=tol-len[x][y]+dis[x][y]; }else{ ans+=tol-len[x][y]+z; } }else{ clr(vis); mindis=INF; lab(x,y); dfs(x,y); dis[x][y]=dis[y][x]=mindis; if(dis[x][y]<z){ ans+=tol-len[x][y]+dis[x][y]; }else{ ans+=tol-len[x][y]+z; } } } printf("%.4f\n",ans/Q); } return 0; }
14 HDU 4354(双指针
题目:一条直线上有若干个城市,每个城市属于一个国家。每次可以消灭一个区间上的城市,花费为区间长度。但是有些国家只能消灭两者之一。求最小花费。
思路:双指针枚举区间就可以做到n^2,但是还有个关键的常熟优化,就是先选前k个城市,然后再开始计算,否则会T!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-14) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000300) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; template <class T> inline bool scan_d(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!='-'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); ret*=sgn; return 1; } inline void out(int x) { if(x>9) out(x/10); putchar(x%10+'0'); } const int maxn=6000; struct city{ int x,c; bool operator < (const city &C)const{return x<C.x;} }a[maxn]; vector<int> G[maxn]; int T; int c,n,k,m; int cnt[2006]; int dp[2005][2]; bool vis[2005]; inline int max(const int &x,const int &y){if(x>y) return x;return y;} void dfs(int v,int f=-1){ dp[v][1]=1,dp[v][0]=0,vis[v]=1; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f||!cnt[u]) continue; dfs(u,v); dp[v][1]+=dp[u][0],dp[v][0]+=max(dp[u][1],dp[u][0]); } } int cal(){ int ans=0; for(int i=1;i<=n;i++) vis[i]=0; for(int i=1;i<=n;i++) if(!vis[i]&&cnt[i]) dfs(i),ans+=max(dp[i][0],dp[i][1]); return ans; } int cas=0; void solve(){ ll ans=1e18; clr(cnt); int i=0,j=0; for(;j<k;j++) cnt[a[j].c]++; for(;i<c;i++){ int res; while((res=cal())<k&&j<c) cnt[a[j].c]++,j++; if(res<k) break; ll cost=abs(a[j-1].x-a[i].x); cnt[a[i].c]--; ans=min(ans,cost); } if(ans==1e18) printf("Case #%d: %d\n",++cas,-1); else printf("Case #%d: %d\n",++cas,(int)ans); } void init(){for(int i=0;i<=n;i++) G[i].clear();} int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); cin>>T; while(T--){ scan_d(c);scan_d(n);scan_d(k);scan_d(m); init(); for(int i=0;i<c;i++){scan_d(a[i].x);scan_d(a[i].c);} sort(a,a+c); for(int i=0;i<m;i++){ int x,y; scan_d(x);scan_d(y); G[x].pb(y); G[y].pb(x); } solve(); } return 0; }
15 HDU 4340(树形dp
题目:给树染两种颜色,每个节点每种颜色有个cost,如果在相邻的节点染了一种颜色,再在当前节点染这种颜色时半价,求最小花费。
思路:dp[i][j][k]表示i节点染成j颜色且j颜色的全价点在/不在i节点的子树里。注意到对于连成一片的同种颜色,必然只有一个全价点。
(本来能半小时一发ac的,结果出题人简直是吃了翔(反正我没看见),居然没说是多组输入。。。。。浪费了一个多小时。。。)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-14) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000300) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=200; int n; int c[maxn][2]; vector<int> G[maxn]; int dp[maxn][2][2]; int a[maxn],b[maxn]; void dfs(int v,int f=-1){ dp[v][0][0]=c[v][0]/2,dp[v][1][0]=c[v][1]/2; int min1=0x3f3f3f3f,min2=0x3f3f3f3f; int sum1=0,sum2=0; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,v); min1=min(min1,dp[u][0][1]-min(dp[u][0][0],dp[u][1][1])); min2=min(min2,dp[u][1][1]-min(dp[u][1][0],dp[u][0][1])); sum1+=min(dp[u][0][0],dp[u][1][1]),sum2+=min(dp[u][1][0],dp[u][0][1]); } dp[v][0][1]=min(sum1+min1+c[v][0]/2,sum1+c[v][0]); dp[v][1][1]=min(sum2+min2+c[v][1]/2,sum2+c[v][1]); dp[v][0][0]+=sum1; dp[v][1][0]+=sum2; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(cin>>n){ for(int i=0;i<=n;i++) G[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&c[i][0]),a[i]=c[i][0]; for(int j=1;j<=n;j++) scanf("%d",&c[j][1]),b[j]=c[j][1]; for(int i=0;i<n-1;i++){ int x,y; scanf("%d%d",&x,&y); G[x].pb(y); G[y].pb(x); } dfs(1); cout<<min(dp[1][1][1],dp[1][0][1])<<endl; } return 0; }
16 CodeForcesGym100589A(分块,树状数组
题目:给一个树的某一层加一个数,或者询问某个子树的权值和。
思路:首先想到转换成序列用树状数组维护区间和,但是单点更新复杂度太高。可以用平方分割的思想处理。如果某一层节点过多,就单独维护一层加的值,否则暴力单点更新bit,不论是更更新bit还是维护单层的值都是O(sqrt(n))的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-14) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000300) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) template <class T> inline bool scan_d(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!='-'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); ret*=sgn; return 1; } inline void out(long long x) { if(x>9) out(x/10); putchar(x%10+'0'); } typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=1e5+300; const int lim=400; int n,m; vector<int> G[maxn],D[maxn]; vector<int> big; bool isbig[maxn]; ll bigcnt[maxn]; int sz=0; int dfn[maxn],head[maxn]; int maxdep=0; void dfs(int v,int d,int f=-1){ maxdep=max(d,maxdep); head[v]=sz+1; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,d+1,v); } dfn[v]=++sz; D[d].pb(sz); } void build(){ for(int i=0;i<n-1;i++){ int x,y; scanf("%d%d",&x,&y); G[x].pb(y); G[y].pb(x); } dfs(1,0); for(int i=0;i<=maxdep;i++){ if(D[i].size()>lim){ big.pb(i); isbig[i]=1; } sort(D[i].begin(),D[i].end()); } } struct BIT{ ll a[maxn]; void add(int p,ll x){ while(p<maxn){ a[p]+=x; p+=p&-p; } } ll sum(int p){ ll ans=0; while(p>0){ ans+=a[p]; p-=p&-p; } return ans; } }B; void update(int L,int Y){ if(isbig[L]) bigcnt[L]+=Y; else{ for(int i=0;i<D[L].size();i++){ int u=D[L][i]; B.add(u,Y); } } } ll query(int x){ int l=head[x],r=dfn[x]; ll ans=B.sum(r)-B.sum(l-1); for(int i=0;i<big.size();i++){ int d=big[i]; int cnt=upper_bound(D[d].begin(),D[d].end(),r)-lower_bound(D[d].begin(),D[d].end(),l); ans+=cnt*bigcnt[d]; } return ans; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(cin>>n>>m){ build(); while(m--){ int op; scanf("%d",&op); if(op==1){ int L,Y; scanf("%d%d",&L,&Y); update(L,Y); }else{ int x; scanf("%d",&x); out(query(x)); puts(""); } } } return 0; }