A:数列下标
题意:找出每个位置右边第一个比自身大的位置 |
思路:单调栈模板题。然而这个题目数据水,竟然暴力都能过
AC代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e4+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'|ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
ll n;
ll r[maxn];
stack<ll> s;
ll a[maxn];
void solve()
{
while(!s.empty()) s.pop();
per(i,n,1)
{
while(s.size()&&a[s.top()]<= a[i]) s.pop();
if(s.empty()) r[i] = 0;
else r[i] = s.top();
s.push(i);
}
rep(i,1,n)
printf("%lld%c",r[i],i==n?'\n':' ');
}
int main()
{
cin>>n;
rep(i,1,n) a[i] = read();
solve();
return 0;
}
B:可持久化动态图上树状数组维护01背包
题意:每个位置取出的代价是a[i]*i,问最小花费 |
思路:挂羊头卖狗肉,别理这个题目可能95%的人都能过。如果全是正数,我们就直接每次挑开头就行了(毕竟每个a[i]都要选,谁不想乘个小的i呢)。如果有负数,那就是能对花费减少的,我希望i越大越好,所以我就从后往前挑负数,因为这样不会影响到前面的负数要乘的i。所以这个题就贪心一下就行了。
AC代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e6+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'|ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
ll a[maxn];
ll b[maxn];
int main()
{
ll n; cin>>n;
rep(i,1,n)
a[i] = read();
ll ans = 0;
per(i,n,1)
{
if(a[i]<=0) ans += a[i]*i;
}
rep(i,1,n) if(a[i]>0) ans += a[i];
cout<<ans<<'\n';
return 0;
}
D:树上求和
题意:给一颗数,修改:对子树+y。查询:子树的平方和 |
思路:先处理一遍dfs序,把这颗树转化成线性的区间来表示。然后用线段树来解决。线段树一个单元多加两个主要的变量,a[i].sum表示区间和,a[i].po表示区间平方和。观察规律发现,其实对【L,R】+ y,对每个元素x其实就增加了2xy + y2,那么总体增加的就是2ysum(l,r) + (r-l+1)y2。后面就是(bug树)线段树的常规操作了
AC代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 2e6+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 23333;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'|ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
vector<vector<ll> > D(maxn);
int n;
ll c[maxn];
ll vis[maxn];
ll L[maxn];
ll R[maxn];
ll idx = 1;
ll arr[maxn];
ll d[maxn];
ll sum1[maxn];
ll sum2[maxn];
typedef struct Tree
{
ll l;
ll r;
ll sum;
ll po;
ll lazy;
} T;
T a[maxn<<2];
void update(ll k)
{
a[k].sum = (a[k<<1].sum + a[k<<1|1].sum)%mod;
a[k].po = (a[k<<1].po + a[k<<1|1].po)%mod;
}
void build_tree(ll k, ll l, ll r)
{
a[k].l = l;
a[k].r = r;
a[k].lazy = 0;
if(l==r)
{
a[k].sum = 0;
a[k].po = 0;
return ;
}
ll mid = (l+r)>>1;
build_tree(k<<1,l,mid);
build_tree(k<<1|1,mid+1,r);
update(k);
}
void pushdown(ll k)
{
if(a[k].l==a[k].r)
{
a[k].lazy=0;
return;
}
ll y = a[k].lazy ;
a[k<<1].po = ( a[k<<1].po + a[k<<1].sum * 2 * y + (a[k<<1].r - a[k<<1].l + 1)* y*y ) % mod;
a[k<<1].sum = (a[k<<1].sum+y * (a[k<<1].r - a[k<<1].l + 1) ) %mod;
y = a[k].lazy ;
a[k<<1|1].po = (a[k<<1|1].po + a[k<<1|1].sum * 2 * y + (a[k<<1|1].r - a[k<<1|1].l + 1)*y*y ) % mod;
a[k<<1|1].sum = (a[k<<1|1].sum + y * (a[k<<1|1].r - a[k<<1|1].l + 1) ) % mod;
a[k<<1].lazy += a[k].lazy;
a[k<<1|1].lazy += a[k].lazy;
a[k].lazy = 0;
}
void change_for_range(ll k, ll l, ll r,ll val)
{
if(a[k].lazy) pushdown(k);
if(a[k].l>r||a[k].r<l) return ;
else if(a[k].l>=l&&a[k].r<=r)
{
a[k].lazy += val;
a[k].po = ( a[k].po + a[k].sum * 2 * val + val*val * (a[k].r - a[k].l + 1) ) % mod;
a[k].sum =( a[k].sum + val*(a[k].r - a[k].l +1) ) % mod;
return ;
}
ll mid = (l+r)>>1;
change_for_range(k<<1,l,r,val);
change_for_range(k<<1|1,l,r,val);
update(k);
}
ll Query_for_range(ll k,ll l, ll r)
{
if(a[k].lazy) pushdown(k);
if(a[k].l>r||a[k].r<l) return 0;
else if(a[k].l>=l&&a[k].r<=r)
{
return a[k].po;
}
return (Query_for_range(k<<1, l, r) + Query_for_range(k<<1|1,l,r) ) % mod;
}
void dfs_for_tree(int x)
{
L[x] = ++idx; //idx初始化为0
for(int i=0;i<D[x].size();i++)
{
vis[x] = 1;
if(!vis[D[x][i]])
dfs_for_tree(D[x][i]);
}
R[x] = idx;
}
void init()
{
idx = 0;
for(int i=1;i<=n;i++)
vis[i]=0, D[i].clear(),c[i]=0;
}
int main()
{
while(~scanf("%d",&n))
{
init();
build_tree(1,1,n);
int m;
scanf("%d",&m);
rep(i,1,n) arr[i] = read();
for(int i=1;i<=n-1;i++)
{
ll x = read(), y = read();
D[x].push_back(y);
D[y].push_back(x);
}
dfs_for_tree(1);
for(int i=1;i<=n;i++) change_for_range(1,L[i],L[i],arr[i]);
for(int i=1;i<=m;i++)
{
ll flag = read();
if(flag==1)
{
ll x = read(), y = read();
ll l = L[x];
ll r = R[x];
change_for_range(1,l,r,y);
}
else
{
ll x = read();
ll l = L[x];
ll r = R[x];
ll res = (Query_for_range(1,l,r))%mod;
printf("%lld\n",res);
}
}
}
return 0;
}