差分
概念也说不清楚,拿一个“奇妙”的类比:普通数组就像是原函数,普通数组的前缀和就像是积分。差分数组就像导数,差分数组的前缀和就是普通数组的对应数。在处理时,普通前缀和处理起来n,用的时候1;差分数组处理时是1,使用的时候是n。
题目Luogu P1083 借教室
可以使用线段树直接过,差分也可以解决这个题。
可以选择二分法,或者倒序减日程,这里选择倒序。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int l[1000006];
int r[1000006];
long long c[1000006];
long long res[1000006];
int n,m;
long long diff[1000006];
long long sum;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&res[i]);
for(int i=1;i<=m;i++){
scanf("%lld%d%d",&c[i],&l[i],&r[i]);
diff[l[i]]+=c[i];
diff[r[i]+1]-=c[i];
}
int j=m;
for(int i=1;i<=n;i++){
sum+=diff[i];
if(sum>res[i]){
while(sum>res[i]){
diff[l[j]]-=c[j];
diff[r[j]+1]+=c[j];
if(l[j]<=i&&r[j]>=i){
sum-=c[j];
}
j--;
}
}
}
if(j==m)cout<<"0\n";
else cout<<"-1"<<endl<<j+1<<endl;
return 0;
}
这里需要按时间对所需房间数进行计算,是有这样连续的顺序的,因此可以使用差分。
树上差分
“奇妙” 无端的类比:
kmp-trie
差分-树上差分
对于树上某条路径上所有点或边进行同一加减操作,然后询问某一点(边)的权值。因为对树的dfs拥有特殊的顺序,所以可以类比普通的差分,可以把起点终点进行正向操作,对起点终点的lca和fa[lca]进行逆向操作,再进行dfs,子树的贡献和即为答案。
模板 Luogu P3128 [USACO15DEC]Max Flow P
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
struct node{
int from;
int to;
node(int a,int b):from(a),to(b){}
node(){}
};
int ans;
struct LCA{
vector<int>G[maxn];
node Edge[2*maxn];
int vis[500005];
int dep[500005];
int diff[500005];
int t;
int n;
int father[maxn][23];
void init(int u){
t=0;
n=u;
for(int i=0;i<n;i++)G[i].clear();
memset(vis,0,sizeof(vis));
}
void addEdge(int fy,int ty){
Edge[t].from=fy;
Edge[t].to=ty;
G[fy].push_back(t);
t++;
}
void dfs(int u,int d){
vis[u]=1;
dep[u]=d;
for(int j=1;(1<<j)<=d;j++){
father[u][j]=father[father[u][j-1]][j-1];
}
for(int i=0;i<G[u].size();i++){
node & e=Edge[G[u][i]];
if(!vis[e.to]){
father[e.to][0]=u;
dfs(e.to,d+1);
}
}
}
void reinit(){
memset(vis,0,sizeof(vis));
}
void dfs_2(int u){
vis[u]=1;
for(int i=0;i<G[u].size();i++){
node & e=Edge[G[u][i]];
if(!vis[e.to]){
dfs_2(e.to);
diff[u]+=diff[e.to];
}
}
ans=max(ans,diff[u]);
}
int lca(int x,int y){
int a=x;
int b=y;
if(dep[a]<dep[b])swap(a,b);
for(int i=22;i>=0;i--){
if(dep[father[a][i]]>=dep[b])a=father[a][i];
if(a==b)return a;
}
for(int i=22;i>=0;i--){
if(father[a][i]!=father[b][i]){
a=father[a][i];
b=father[b][i];
}
}
return father[a][0];
}
}LcA;
int n,m,s;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
LcA.addEdge(a,b);
LcA.addEdge(b,a);
}
LcA.dfs(1,1);
/*for(int i=1;i<=n;i++){
printf("%d: ",i);
for(int j=0;(1<<j)<=LcA.dep[i];j++){
printf("%d ",LcA.father[i][j]);
}
printf("\n");
}*/
for(int i=1;i<=m;i++){
int x;int y;
scanf("%d%d",&x,&y);
LcA.diff[x]++;
LcA.diff[y]++;
int anc=LcA.lca(x,y);
LcA.diff[anc]--;
LcA.diff[LcA.father[anc][0]]--;
}
LcA.reinit();
LcA.dfs_2(1);
cout<<ans<<endl;
return 0;
}
蒟蒻只会倍增LCA 只是模板数据没有卡。orz