-(rmq)K - A Magic Lamp HDU - 3183
-(离散化+离线处理)L - Turing Tree HDU - 3333
-(dfs序图建树)M - Apple Tree POJ - 3321
-(lazypushdown最大值次大值)N - Gorgeous Sequence HDU - 5306
-(简单题)P - The Child and Sequence CodeForces - 438D
(rmq)K - A Magic Lamp HDU - 3183
rmq入门(这里dp指的是从i到j范围内最小值最小数组从1开始)https://blog.csdn.net/weixin_43331783/article/details/95618122 题解:1中删掉四个数留两个数。所以第一个数字一定是1,5内的。所以在15之间搜寻最小值作为第一个数假设位置为x而第二个值肯定在x,6之间。所以用rmq维护一下最小值即可。#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
#define rmq_log2(x,val) while((1<<(x+1))<=val)x++;
const int maxn=1e3+3;
char a[maxn];
int dp[maxn][maxn];
int n;
int MIN(int a1,int c){
return a[a1]<=a[c]?a1:c;}
void rmq_init()
{
memset(dp,0, sizeof(dp));
for(int i=1;i<=n;i++)
dp[i][0]=i;//初始化
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dp[i][j]=MIN(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r)
{
int k=0;
rmq_log2(k,r-l+1);
return MIN(dp[l][k],dp[r-(1<<k)+1][k]);
}
vector<int> v;
int main()
{
int m;
while(~scanf("%s%d",a+1,&m)) {
n = strlen(a+1);
v.clear();
rmq_init();
m=n-m;
int pos=1;
while (m--) {
pos = rmq(pos, n-m);
v.push_back(pos);
pos++;
}
int flag=0;
for(int i=0;i<v.size();i++){
if(flag){
cout<<a[v[i]];
}
else {
while(a[v[i]]=='0'&&i<v.size()) i++;
if(i<v.size()){cout<<a[v[i]];flag=1;}
}
}
if(flag==0)cout<<0<<endl;
else cout<<endl;
}
}
Turing Tree HDU - 3333
http://acm.hdu.edu.cn/showproblem.php?pid=3333题解链接:https://blog.csdn.net/T__TSZ/article/details/77529140
题解我懒得打。这个题解可以的。由于这里重点在离散化所以下面的代码直接是从代码基础改的。用离散模板改的。实测比原答案快。
#include<iostream>
#include<algorithm>
#include <vector>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls o<<1
#define rs o<<1|1
#define lson L,mid,ls
#define rson mid+1,R,rs
#define mdzz int mid=(L+R)>>1;
int N,M;
long long tree[120005];
int s[30005];
int hashs[30005];
int vis[30005];
long long ans[100003];
struct node
{
int l,r,t;
bool operator <(const node &a)const
{
return a.r>r;
}
}q[200003];
void pushup(int o){
tree[o]=tree[ls]+tree[rs];
}
void update(int p,int L,int R,int o,int v){ //点修改
if(L==R){
tree[o]+=v;
return;
}
mdzz;
if(p<=mid) update(p,lson,v);
else update(p,rson,v);
pushup(o);
}
long long query(int l,int r,int L,int R,int o){//[l,r]区间询问
if(r>=R&&l<=L) return tree[o];
mdzz;
long long ans=0;
if(l<=mid)
ans+=query(l,r,lson);
if(r>mid)
ans+=query(l,r,rson);
return ans;
}
vector<int> v;
int getid(int k)
{
return lower_bound(v.begin(),v.end(),k)-v.begin()+1;
}
int main()
{
int T;
scanf("%d",&T);
int a,b;
while(T--)
{
memset(vis,0,sizeof vis);
memset(tree,0,sizeof tree);
memset(hashs,0,sizeof hashs);
scanf("%d",&N);
for(int i=1;i<=N;i++){scanf("%d",&s[i]);
v.push_back(s[i]);}
scanf("%d",&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].t=i;
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
sort(q+1,q+M+1);
int p=1;
for(int i=1;i<=M;i++)
{
while(p<=q[i].r)
{
int temp=getid(s[p]);
if(vis[temp])
update(vis[temp],1,N,1,-s[p]);
vis[temp]=p;
update(p,1,N,1,s[p]);
p++;
}
ans[q[i].t]=query(q[i].l,q[i].r,1,N,1);
}
for(int i=1;i<=M;i++)printf("%lld\n",ans[i]);
}
return 0;
}
(dfs序图建树)M - Apple Tree POJ - 3321
也是有趣的一道题展示懒得写题解晚点再说。#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1, ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --)
#define rmq_log2(x,val) while((1<<(x+1))<=val)x++;
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; }
typedef long long ll;
const int maxn = 100100;
const double eps = 1e-8;
ll MOD = 1000000007;
struct Edge{
int u,v,next;
}edge[maxn];
int cou;
int node[maxn];
void add(int u,int v){
edge[cou].u=u;
edge[cou].v=v;
edge[cou].next=node[u];
node[u]=cou++;
}
int st[(maxn<<2)+5];
void build(int o,int l,int r){
if(l==r){
st[o]=1;
return ;
}
int m=(l + r)>>1;
build(o<<1,l,m);
build((o<<1)|1,m+1,r);
st[o]=st[o<<1]+st[(o<<1)|1];
}
void update(int o,int l,int r,int ind){
if(l==r){
// if(st[o])st[o]=0;
// else st[o]=1;
// return;
st[o] = !st[o];
return;
}
int m=(l + r)>>1;
if(ind<=m){
update(o<<1,l,m,ind);
}
else{
update((o<<1)|1,m+1,r,ind);
}
st[o]=st[o<<1]+st[(o<<1)|1];
}
int query(int o,int l,int r,int ql,int qr){
// if(ql>r||qr<l) return 0;
if(ql<=l&&qr>=r) return st[o];
// int m=l+((r-l)>>1);
// int p1=query(o<<1,l,m,ql,qr),p2=query((o<<1)|1,m+1,r,ql,qr);
// return p1+p2;
int m = (l + r)>>1;
int ans = 0;
if(ql <= m)ans += query(o<<1,l,m,ql,qr);
if(qr > m)ans += query((o<<1)|1,m+1,r,ql,qr);
return ans;
}
int news;
int so[maxn][2];
void dfs(int now){
news++;
so[now][0]=news;
for(int i=node[now];i!=-1;i=edge[i].next){
dfs(edge[i].v);
}
so[now][1]=news;
}
int main() {
int n;
while (~scanf("%d", &n)) {
if (n == 0)break;/**/
int x, y;
cou = 0;
memset(node, -1, sizeof(node));//
for (int i = 1; i < n; i++) {
scanf("%d%d",&x,&y);
add(x, y);
}
memset(so, 0, sizeof(so));
news = 0;
dfs(1);
build(1, 1, n);
// cout<<1<<endl;
int m;
scanf("%d", &m);
char s[4];
int d;
// scanf("%s%d",op,&x);
while (m--) {
scanf("%s%d", s, &d);
// cout<<n<<endl;
if (s[0] == 'Q') {
printf("%d\n",query(1,1,n,so[d][0],so[d][1]));
} else if (s[0] == 'C') {
update(1, 1, n, so[d][0]);
}
}
}
return 0;
}
(最大值次大值)N - Gorgeous Sequence HDU - 5306
题解链接:https://blog.csdn.net/Nowara_Shinnosuke/article/details/72733223 操作:1.查询区间最大值2.查询区间和3。给一个数更新所有比他大的全部更新。前两个为常见操作不说了。最后一个如果按照常规操作要给定范围节点都遍历到不可,所以记录最大次大值更新的时候及时返回( 如果最大值都大于所给值不需要往下跑了或者节点范围小于所给区间也暂时不用跑了)复杂度0(mlogn)
其实这道题没那么复杂,最大值次大值都是为了lazy更新所用。就是一个需要用到lazy操作的树。 这道题就用到了lazy。当这个节点的max值改变的时候就说明lazy赋值了(没有明显写出lazy是啥)什么是lazy呢? 简单来讲有事才用,没事不用。
比如说,假设有一个2的节点,连着一个3的子节点。从1开始更新,到2时发现符合条件不用更新了(这道题当节点区间小于所给区间并且最大值需要更新(所给值4最大值2)那么把这个节点更新就可以了,不用更新到子节点)那么3就不走过去了。
但是如果有一天要更新3的节点呢?这时候如果只把新的操作给3(所给值3原最大值2)那么3的最大值是3吗?不对应该是4.为什么会这样 刚刚lazy没到这里来。所以这个时候我们就需要 pushdown也就是该用的时候就用。那么有了这个当心操作来的时候会现在把之前的更新了(2变为4)再去更新现在的。
同理,查询也是。原本到2停了,现在我要查3的值那么就需要先更新这样得到4,不然的话就会得到2.
然而每个节点都需要pushdown吗如果刚刚根本已经没有在节点停住也就数lazy为0那就不用再pushdown了。所以pushdow先判断一下lazy是否为0(这道题稍微隐晦了一下,当最大只改变的时候其实lazy就有之了为什么自己想一下不难。所以本质是相同的。)
正确代码看连接。
以下为我的代码。re了不知道为什么,找太久bug了,先放过晚点再说。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson rt<<1, l, m
#define rson rt<<1|1, m+1, r
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --)
#define rmq_log2(x,val) while((1<<(x+1))<=val)x++;
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; }
typedef long long ll;
const int maxn = 100100;
const int Maxn=1e6+10;
const double eps = 1e-8;
ll MOD = 1000000007;
int Max[Maxn<<2],sec[Maxn<<2],num[Maxn<<2];
ll tree[Maxn<<2];
void spup(int rt,int val){//specialupdate
if(Max[rt]<=val) return;
tree[rt]-=1ll*num[rt]*(Max[rt]-val);
Max[rt]=val;
}//?
void pushdown(int rt){
spup(rt<<1,Max[rt]);
spup(rt<<1|1,Max[rt]);
}//?
void pushup(int rt){
// int l=rt<<1,r=rt<<1|1;
// sec[rt]=max(sec[l],sec[r]);
// if(Max[l]<Max[r]){
// Max[rt]=Max[r];
// sec[rt]=max(sec[rt],Max[l]);
// num[rt]=num[r];
// }
// else{
// Max[rt]=Max[l];
// sec[rt]=max(sec[rt],Max[r]);
// num[rt]=num[l];
// }
// tree[rt]=tree[l]+tree[r];
int l=rt<<1,r=rt<<1|1;
tree[rt]=tree[l]+tree[r];
sec[rt]=max(max(sec[l],sec[r]),Max[l]==Max[r]?0:min(Max[l],Max[r]));
Max[rt]=max(Max[l],Max[r]);
num[rt]=0;
if(Max[rt]==Max[l]) num[rt]+=num[l];
if(Max[rt]==Max[r]) num[rt]+=num[r];
}
void build(int rt,int l,int r){
sec[rt]=-1;
if(l==r){
scanf("%d",&Max[rt]);
tree[rt]=(ll)Max[rt];
num[rt]=1;
return ;
}
else{
int m=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
}
void update(int rt,int l,int r,int rl,int rr,int val){
if(val>=Max[rt]) return;
if(rl<=l&&r<=rr&&val>sec[rt]){
spup(rt,val);
return;
}
pushdown(rt);
int m=l+r>>1;
if(rl<=m){
update(lson,rl,rr,val);
}
if(m<rr){
update(rson,rl,rr,val);
}
pushup(rt);
}
ll qsum(int rt,int l,int r,int rl,int rr){
if(rl<=l&&rr>=r) return tree[rt];
pushdown(rt);
int m=l+r>>1;
ll ans=0;
if(l<=m){
ans+=qsum(lson,rl,rr);
}
if(r>m){
ans+=qsum(rson,rl,rr);
}
return ans;
}
int qmax(int rt,int l,int r,int rl,int rr){
if(rl<=l&&rr>=r) return Max[rt];
pushdown(rt);
int m=l+r>>1;
ll ans=0;
if(l<=m){
ans=max(ans,qsum(lson,rl,rr));
}
if(r>m){
ans=max(ans,qsum(rson,rl,rr));
}
return ans;
}
int main(){
int t,m,n;scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--){
int a,b,c,d;
scanf("%d",&a);
if(a==0){
scanf("%d%d%d",&b,&c,&d);
update(1,1,n,b,c,d);
}
else if(a==1){
scanf("%d%d",&b,&c);
printf("%d\n",qmax(1,1,n,b,c));
}
else{
scanf("%d%d",&b,&c);
printf("%lld\n",qsum(1,1,n,b,c));
}
}
}
}
(简单题)P - The Child and Sequence CodeForces - 438D
给一个序列 支持3种操作 1 u v 对于所有i u<=i<=v,输出a[i]的和 2 u v t 对于所有i u<=i<=v a[i]=a[i]%t 3 u v 表示a[u]=v(将v赋值给a[u]) n,q<=1e5 a[i],t,v<=1e9#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXM=1e6+10;//定义 MAXM 为线段最大长度
typedef long long ll;
ll tree[(MAXM<<2)+5],mx[(MAXM<<2)+5];
#define lson ro<<1, l, m
#define rson ro<<1|1, m+1, r
void pushup(int ro){
tree[ro]=tree[ro<<1]+tree[ro<<1|1];
mx[ro]=max(mx[ro<<1],mx[ro<<1|1]);
};
void build(int ro,int l,int r){
if(l==r){
scanf("%lld",&tree[ro]);
mx[ro]=tree[ro];
return ;
}
else{
int m=l+r>>1;
build(lson);
build(rson);
pushup(ro);
}
}
void update(int ro,int l,int r,int rl,int rr,int mod){
if(rl<=l&&r<=rr){
if(mx[ro]<mod)return;
if(l==r) {
tree[ro] %= mod;
mx[ro] %= mod;
return;
}
}
int m=l+r>>1;
if(rl<=m){
update(lson,rl,rr,mod);
}
if(m<rr){
update(rson,rl,rr,mod);
}
pushup(ro);
}
void update1(int ro,int l,int r,int index,int val){
if(l==r){
tree[ro]=val;
mx[ro]=val;
return;
}
int m=l+r>>1;
if(index<=m){
update1(lson,index,val);
}
if(m<index){
update1(rson,index,val);
}
pushup(ro);
}
ll query(int ro,int l,int r,int rl,int rr){
if(rl<=l&&r<=rr) return tree[ro];
int m=l+r>>1;
ll ans=0;
if(rl<=m){
ans+=query(lson,rl,rr);
}
if(rr>m){
ans+=query(rson,rl,rr);
}
return ans;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
build(1,1,n);
while(q--){
int op,u,v;
scanf("%d%d%d",&op,&u,&v);
if(op==1){
printf("%lld\n",query(1,1,n,u,v));
}
else if(op==2){
int mod;
scanf("%d",&mod);
update(1,1,n,u,v,mod);
}
else if(op==3){
update1(1,1,n,u,v);
}
}
}