还没更完
引子
本文是按照李超老师的线段树ppt学习的学习记录以及一些心得
cf145E
题意
两个操作:
1.翻转\([l,r]\)中的0和1
2.求\([l,r]\)的最长不下降子序列长度
思路
线段树维护00,01,10,11的长度,翻转就是交换(00,11)和(01,10)
答案就是max(00-00,00-01,00-11,01-11,11-11)
代码
Code
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PI;
typedef pair PLL;
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);
int len00[maxn<<2],len01[maxn<<2],len11[maxn<<2],len10[maxn<<2];
int flg[maxn<<2];
int a[maxn];
int n,m;
void pushup(int l, int r, int root){
int mid = (l+r)>>1;
len00[root]=len00[lc]+len00[rc];
len01[root]=max(len00[lc]+max(len01[rc],len11[rc]),len01[lc]+len11[rc]);
len10[root]=max(len11[lc]+max(len10[rc],len00[rc]),len10[lc]+len00[rc]);
len11[root]=len11[lc]+len11[rc];
return;
}
void build(int l, int r, int root){
int mid = (l+r)>>1;
if(l==r){
if(a[l])len11[root]=1;
else len00[root]=1;
return;
}
build(lson);build(rson);
pushup(l,r,root);
return;
}
void pushdown(int l, int r, int root){
int mid = (l+r)>>1;
if(flg[root]){
flg[lc]^=1;flg[rc]^=1;
flg[root]^=1;
swap(len00[lc],len11[lc]);swap(len00[rc],len11[rc]);
swap(len01[lc],len10[lc]);swap(len01[rc],len10[rc]);
}
}
void update(int x, int y, int l, int r, int root){
int mid = (l+r)>>1;
if(x<=l&&r<=y){
flg[root]^=1;
swap(len00[root],len11[root]);
swap(len01[root],len10[root]);
return;
}
pushdown(l,r,root);
if(x<=mid)update(x,y,lson);
if(mid>1;
if(l==r)return;
pushdown(l,r,root);
gao(lson);gao(rson);
return;
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%1d", &a[i]);
a[i]=(a[i]==4?0:1);
}
build(1,n,1);
for(int i = 1; i <= m; i++){
char op[66];
scanf("%s",op+1);
if(op[1]=='s'){
int l, r;
scanf("%d %d", &l, &r);
update(l,r,1,n,1);
}
else{
int ans = 0;
ans=max(ans,len11[1]);
ans=max(ans,len01[1]);
ans=max(ans,len00[1]);
printf("%d\n",ans);
}
}
return 0;
}
BZOJ1103
题意
一棵树,初始每条边都是1,两个操作:
1.将某个边改为0
2.问一个点到根的边权和
思路
法一
线段树维护dfs序,操作1为区间修改,操作2为单点查询
这题10s时限,加了快读跑了9s。。
代码
Code
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PI;
typedef pair PLL;
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);
inline int read(){
int num;
char ch;
while((ch=getchar())'9');
num=ch-'0';
while((ch=getchar())>='0' && ch<='9'){
num=num*10+ch-'0';
}
return num;
}
vectorv[maxn];
int n,q;
int S[maxn];
int bg[maxn],ed[maxn];
int tot;
int a[maxn];
void dfs(int x, int fa, int cnt){
S[++tot]=x;
bg[x]=tot;
a[tot]=cnt;
for(int i = 0; i < (int)v[x].size(); i++){
int y = v[x][i];
if(y==fa)continue;
dfs(y,x,cnt+1);
}
ed[x]=tot;
}
int sum[maxn<<2],addv[maxn<<2];
void build(int l, int r, int root){
int mid = (l+r)>>1;
if(l==r){
sum[root]=a[l];
return;
}
build(lson);build(rson);
sum[root]=sum[lc]+sum[rc];
return;
}
void pushdown(int l, int r, int root){
int mid = (l+r)>>1;
if(addv[root]!=0){
addv[lc]+=addv[root];
addv[rc]+=addv[root];
sum[lc]+=(mid-l+1)*addv[root];
sum[rc]+=(r-mid)*addv[root];
addv[root]=0;
}
}
void update(int x, int y, int add, int l, int r, int root){
int mid = (l+r)>>1;
if(x<=l&&r<=y){
addv[root]+=add;
sum[root]+=add*(r-l+1);
return;
}
pushdown(l,r,root);
if(x<=mid)update(x,y,add,lson);
if(y>mid)update(x,y,add,rson);
sum[root]=sum[lc]+sum[rc];
return;
}
int ask(int l, int r, int root, int x){
int mid = (l+r)>>1;
if(l==r)return sum[root];
pushdown(l,r,root);
if(x<=mid)return ask(lson,x);
else return ask(rson,x);
}
int main(){
n=read();
tot = 0;
for(int i = 1; i < n; i++){
int x, y;
x=read();y=read();
v[x].pb(y);v[y].pb(x);
}
dfs(1,-1,0);
build(1,n,1);
scanf("%d", &q);
for(int i = 1; i < q+n; i++){
char op[5];
int x, y;
scanf("%s",op+1);
if(op[1]=='W'){
x=read();
//scanf("%d", &x);
printf("%d\n",ask(1,n,1,bg[x]));
}
else{
x=read();y=read();
//scanf("%d %d", &x ,&y);
if(x>y)swap(x,y);
update(bg[y],ed[y],-1,1,n,1);
}
}
return 0;
}
法二
建欧拉序,进入的权值为1,退出的权值为-1
操作1为修改进入和退出的权值为0
操作2为查询前缀和
树状数组即可
跑了5s
代码
Code
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
using namespace std;
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PI;
typedef pair PLL;
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 8e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);
inline int read(){
int num;
char ch;
while((ch=getchar())'9');
num=ch-'0';
while((ch=getchar())>='0' && ch<='9'){
num=num*10+ch-'0';
}
return num;
}
int lowbit(int x){
return x&-x;
}
int n,q;
int tot;
int tree[maxn<<2];
void add(int x,int C){
//printf("***add %d %d\n",x,C);
for(int i=x;i<=tot;i+=lowbit(i)){
tree[i]+=C;
}
}
int sum(int x){
int ans=0;
//printf("***sum %d\n",x);
for(int i=x;i;i-=lowbit(i)){
ans+=tree[i];
}
return ans;
}
vectorv[maxn];
int S[maxn];
int bg[maxn],ed[maxn];
int a[maxn];
void dfs(int x, int fa, int cnt){
S[++tot]=x;
bg[x]=tot;
a[tot]=1;
for(int i = 0; i < (int)v[x].size(); i++){
int y = v[x][i];
if(y==fa)continue;
dfs(y,x,cnt+1);
}
S[++tot]=x;
a[tot]=-1;
ed[x]=tot;
}
int main(){
n=read();
tot = 0;
for(int i = 1; i < n; i++){
int x, y;
x=read();y=read();
v[x].pb(y);v[y].pb(x);
}
dfs(1,-1,0);
for(int i = 1; i <= n; i++){
add(bg[i],1);add(ed[i],-1);
}
scanf("%d", &q);
for(int i = 1; i < q+n; i++){
char op[5];
int x, y;
scanf("%s",op+1);
if(op[1]=='W'){
x=read();
printf("%d\n",sum(bg[x])-1);
}
else{
x=read();y=read();
if(x>y)swap(x,y);
add(bg[y],-1);add(ed[y],1);
}
}
return 0;
}
Code