字典树的学习真的很麻烦,线段也是
关于数组优化运用的示例
#include<bits/stdc++.h>
using namespace std;
#define maxn 100007 //元素总个数
int a[maxn],n;//存原数组下标[1,n]
void init (int n){for(int i = 1; i<=n;i++)a[i]=0;}
int main()
{
while(~scanf("%d", &n)!=EOF)
{
if(n==0)break;
init(n);
for(int i = 1; i <= n; i++)
{
int l,r;
cin>>l>>r;
a[l]++;
a[r+1]--;
}
for(int i = 1; i <= n; i++)
{
if(i==1)printf("%d", a[1]);
else
{
a[i]+=a[i-1];
printf(" %d", a[i]);
}
}
cout<<endl;
}
return 0;
}
/*1 4
1 0 0 0 1
1 1 1 1 1*/
学习理解中
#include <bits/stdc++.h>
using namespace std;
int fa[105];
int find(int n)
{
if(fa[n]==n) return n;
else return fa[n]=find(fa[n]);
}
struct Node{
int x,y;
}node[105];
bool check(Node a,Node b)
{
if(a.x==b.x) return 1;
else if(a.y==b.y)return 1;
else return 0;
}
set<int> cnt;
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
fa[i]=i;
cin>>node[i].x>>node[i].y;
for(int j=0;j<i;j++)
{
if(check(node[i],node[j])){
fa[find(j)]=find(i);
// cout<<fa[j]<<endl;
}
}
}
for(int i=0;i<n;i++)
{
//cout<<find(fa[i])<<endl;
cnt.insert(find(i));
}
cout<<cnt.size()-1<<endl;
}
及离散化树状数组
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=500005;
int a[maxn],c[maxn];
int n;
struct org
{
int v, f;
}b[maxn];
int cmp(org a,org b)
{
return a.v<b.v;
}
int lowbit(int i)
{
return i&(-i);
}
int update(int i,int x)
{
while(i<=maxn)
{
c[i]=c[i]+x;
i=i+lowbit(i);
}
//cout<<"1"<<endl;
}
int query(int i)
{
int sum=0;
while(i>0)
{
sum+=c[i];
i=i-lowbit(i);
}
return sum;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i].v);
b[i].f=i;
}
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
{
a[b[i].f]=i;
}
long long sum=0;
for(int i=1;i<=n;i++)
{
update(a[i],1);
sum+=i-query(a[i]);
}
cout<<sum<<endl;
}
return 0;
}
以下为大纲内容
树状数组 支持的操作 快速求前缀和 O(logn)O(logn) 修改某一个数 O(logn)O(logn) 对比 求前缀和 修改 数组储存
O(n)O(n) O(1)O(1) 维护前缀和数组 O(1)O(1) O(n)O(n) 基本原理 二进制 \large
x=2{i_k}+2{i_{k-1}}+2{i_{k-2}}+…+2{i_1}x=2 i k +2 i k−1
+2 i k−2 +…+2 i 1
v_k\leq v_{k-1}\leq v_{k-2}\leq…\leq v_{1}v k ≤v k−1 ≤v k−2 ≤…≤v 1 ,kk是递减的,所以有 k\leq log_2xk≤log 2 x 求 00~xx
区间的数之和可以按如下方案分解 \large (x-2^{i_1 },x](x−2 i 1 ,x] \large
2^{i_1}2 i 1
个数,2^{i_1}2 i 1
是 xx 的二进制表示的最后一个11 \large (x-2{i_1}-2{i_2},x-2^{i_1}](x−2 i 1 −2 i 2 ,x−2 i 1 ] \large 2^{i_2}2 i 2
个数,2^{i_2}2 i 2
是 x-2^{i_1}x−2 i 1
的二进制表示的最后一个11 …… \large (0,x-2{i_1}-2{i_2}-…-2^{k-1}](0,x−2 i 1 −2 i 2 −…−2 k−1 ] \large 2^{i_k}2 i k
个数 如何维护这每一个区间和呢?观察区间数的性质 区间 (L,R](L,R] 的长度一定是 RR 的二进制表示的最后一个 11 所对应的二次幂 (L,R]=[R-lowbit®+1,R](L,R]=[R−lowbit®+1,R] , lobit(x)=x
&(-x)lobit(x)=x&(−x) ,用 c[R]c[R] 表示 11~nn 个数,最多只会有 nn 个区间,因为由右端点唯一确定
c[x]=a[x-lowbit(x)+1,x]c[x]=a[x−lowbit(x)+1,x] ,以 xx 为右端点,区间所有数之和 对于
x=…100…0x=…100…0 有 kk 个零,c[x]=以x结尾的,长度是2^k的区间之和c[x]=以x结尾的,长度是2 k
的区间之和 儿子的形式0…01…10…0 把儿子累加起来
c[x]=ax+c{x-1}+c{x-1-lowbit(x-1)}c[x]=ax+cx−1+cx−1−lowbit(x−1)
直到0为止,麻烦 父节点找子节点 子节点找父节点,修改操作 找到所有包含 xx 的 假设 pp 是父节点 …10…0…10…0
它的所有子节点…01…10…0…01…10…0 从11开始kk位,逆向上一步
加上0000000000000010…00000000000000010…0 直接影响的区间是唯一的
p=x+lowbit(x)p=x+lowbit(x) 迭代直接影响的区间,没走一次末尾0加一,logxlogx次
for(i=x;i<=n;i+=lobit(i) tr[i]+=c; 查询 11~xx: for(i=x;i;i-=lobit(i))
tr[i]-=c; 扩展 和差分结合 和差分结合配合公式 线段树 pushup由子节点计算父节点信息 pushdown由父节点下传到子节点
操作 pushup build 将区间初始化为线段树 modify 修改 单点修改 区间修改 pushdown query 查询 二叉树
数组模拟链表